cabalist 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. data/.gitignore +4 -0
  2. data/.travis.yml +4 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +0 -0
  5. data/README.md +121 -0
  6. data/Rakefile +17 -0
  7. data/cabalist.gemspec +42 -0
  8. data/lib/cabalist.rb +13 -2
  9. data/lib/cabalist/configuration.rb +20 -0
  10. data/lib/cabalist/frontend.rb +111 -0
  11. data/lib/cabalist/model_additions.rb +127 -0
  12. data/lib/cabalist/railtie.rb +14 -0
  13. data/lib/cabalist/version.rb +3 -0
  14. data/lib/cabalist/views/classifier.haml +82 -0
  15. data/lib/cabalist/views/index.haml +21 -0
  16. data/lib/cabalist/views/layout.haml +39 -0
  17. data/lib/generators/cabalist/classifier/USAGE +0 -0
  18. data/lib/generators/cabalist/classifier/classifier_generator.rb +37 -0
  19. data/lib/generators/cabalist/classifier/templates/migrations/add_cabalist.rb.erb +11 -0
  20. data/lib/generators/cabalist/install/USAGE +0 -0
  21. data/lib/generators/cabalist/install/install_generator.rb +26 -0
  22. data/lib/generators/cabalist/install/templates/initializers/cabalist.rb +4 -0
  23. data/lib/generators/cabalist/install/templates/public/images/eye_12x9.png +0 -0
  24. data/lib/generators/cabalist/install/templates/public/images/logo.png +0 -0
  25. data/lib/generators/cabalist/install/templates/public/images/ncirl.png +0 -0
  26. data/lib/generators/cabalist/install/templates/public/images/pen_12x12.png +0 -0
  27. data/lib/generators/cabalist/install/templates/public/images/symbol.png +0 -0
  28. data/lib/generators/cabalist/install/templates/public/images/target_12x12.png +0 -0
  29. data/lib/generators/cabalist/install/templates/public/images/x_14x14.png +0 -0
  30. data/lib/generators/cabalist/install/templates/public/javascripts/cabalist.js +23 -0
  31. data/lib/generators/cabalist/install/templates/public/stylesheets/cabalist.css +197 -0
  32. data/spec/cabalist/frontend_spec.rb +79 -0
  33. data/spec/cabalist/model_additions_spec.rb +104 -0
  34. data/spec/cabalist/performance_benchmark_spec.rb +76 -0
  35. data/spec/spec_helper.rb +30 -0
  36. metadata +164 -12
  37. data/lib/cabalist/manager.rb +0 -30
  38. data/lib/cabalist/object_hooks.rb +0 -59
@@ -0,0 +1,14 @@
1
+ require 'rails'
2
+ require 'active_record'
3
+
4
+ module Cabalist
5
+ class Railtie < ::Rails::Railtie
6
+
7
+ initializer 'cabalist.model_additions', do
8
+ ActiveSupport.on_load :active_record do
9
+ extend ModelAdditions
10
+ end
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ module Cabalist
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,82 @@
1
+ .content
2
+
3
+ %ul.scopes
4
+ %lh= "#{klass} classifier:"
5
+ %li
6
+ %a{ :href => "/cabalist/#{klass.to_s.downcase}/all" } All
7
+ %li
8
+ %a{ :href => "/cabalist/#{klass.to_s.downcase}/none" } Not Classified
9
+ %li
10
+ %a{ :href => "/cabalist/#{klass.to_s.downcase}/manual" } Manually Classified
11
+ %li
12
+ %a{ :href => "/cabalist/#{klass.to_s.downcase}/auto" } Automatically Classified
13
+
14
+ - unless @collection.empty?
15
+ %table.cabalist_records
16
+ %thead
17
+ %tr
18
+ %td ID
19
+ - klass.classifier.data_set.data_labels.each do |l|
20
+ %td= l.to_s.humanize.titlecase
21
+ %td.center Actions
22
+ %tbody
23
+ - @collection.each do |el|
24
+ %tr
25
+ %td= el.id
26
+ - el.get_features.each do |feature|
27
+ %td= feature.to_s
28
+ %td= el.get_class_variable.to_s
29
+ %td.center
30
+
31
+ %img{ :src => '/images/eye_12x9.png',
32
+ :class => 'show_icon',
33
+ :title => 'Show classified object' }/
34
+ .overlay.show_widget
35
+ .dialog-widget
36
+ .dialog-content
37
+ %img{ :src => '/images/x_14x14.png', :class => 'close_icon' }/
38
+ %pre= el.attributes.to_yaml
39
+
40
+ %img{ :src => '/images/pen_12x12.png',
41
+ :class => 'edit_icon',
42
+ :title => 'Manually classify' }/
43
+ .overlay.edit_widget
44
+ .dialog-widget
45
+ .dialog-content
46
+ %img{ :src => '/images/x_14x14.png', :class => 'close_icon' }/
47
+
48
+ -# This form is for manual classification of Cabalist objects. --------- #
49
+ %form{ :action => "/cabalist/#{klass.to_s.downcase}/teach/#{el.id}",
50
+ :method => 'POST' }
51
+ %p.label= "#{el.class.get_class_variable_name.to_s.humanize.titlecase}:"
52
+ %span.label_info Use existing class:
53
+ %select{ :name => 'classification' }
54
+ %option{ :value => nil } - choose classification -
55
+ - el.class.classifier.data_set.build_domain(-1).to_a.each do |opt|
56
+ %option{ :value => opt.to_s,
57
+ :selected => (el.get_class_variable == opt) }= opt
58
+ %p
59
+ %span.label_info ...or add a new one:
60
+ %input{ :name => 'classification_freeform', :value => '' }/
61
+ %p
62
+ %input{ :type => 'submit', :value => 'Teach!' }/
63
+
64
+ -# This is the for for autoclassification of Cabalist objects. --------------- #
65
+ %form{ :action => "/cabalist/#{klass.to_s.downcase}/autoclassify/#{el.id}",
66
+ :method => 'POST', :class => 'autoclassify' }
67
+ %input{ :type => 'image',
68
+ :src => '/images/target_12x12.png',
69
+ :title => "Autoclassify (#{el.classify.to_s})" }/
70
+
71
+
72
+ %table.kaminari_nav
73
+ %tr
74
+ %td.previous
75
+ - if page.to_i > 1
76
+ %a{ :href => "/cabalist/#{klass.to_s.downcase}/#{scope}/#{page-1}" } &laquo; Previous
77
+ %td.next
78
+ - if (page * Cabalist::Frontend::PER_PAGE) < total
79
+ %a{ :href => "/cabalist/#{klass.to_s.downcase}/#{scope}/#{page+1}" } Next &raquo;
80
+
81
+ - else
82
+ %p No data here yet.
@@ -0,0 +1,21 @@
1
+ .content
2
+
3
+ %h1 Dashboard
4
+
5
+ %ul.classifiers
6
+ - @classes.each do |klass|
7
+ %li
8
+ %ul.specs
9
+ %lh
10
+ = klass.to_s
11
+ classifier
12
+ %li
13
+ Classifies the
14
+ %span.attr_name= klass.classifier.data_set.data_labels[-1]
15
+ attribute
16
+ %li
17
+ = klass.classifier.data_set.data_items.length
18
+ data points
19
+ %li
20
+ Signals:
21
+ %span.attr_name= klass.classifier.data_set.data_labels[0...-1].join(', ')
@@ -0,0 +1,39 @@
1
+ !!! 5
2
+
3
+ %html
4
+ %head
5
+ %title= "Cabalist | #{@app_name}"
6
+ %link{ :href => '/stylesheets/cabalist.css',
7
+ :rel => 'stylesheet',
8
+ :type => 'text/css' }/
9
+ %script{ :src => '/assets/jquery.js',
10
+ :type => 'text/javascript' }
11
+ %script{ :src => '/javascripts/cabalist.js',
12
+ :type => 'text/javascript' }
13
+ %body
14
+ %header
15
+ .container
16
+ %a.logo{ :href => '/cabalist' }
17
+ %img{ :src => '/images/logo.png' }/
18
+ %nav
19
+ - @classes.each do |klass|
20
+ %a{ :href => "/cabalist/#{klass.to_s.downcase}/all" }= klass.to_s.pluralize
21
+
22
+ = yield
23
+
24
+ %footer
25
+ %p
26
+ Cabalist is an open source Ruby library developed by
27
+ %a{ :href => 'http://github.com/marcinwyszynski/' } Marcin Wyszynski.
28
+ AI algorithms come from
29
+ %a{ :href => 'http://ai4r.rubyforge.org/' } ai4r
30
+ gem. Layout shamesly stolen from
31
+ = succeed '.' do
32
+ %a{ :href => 'http://redis.io/' } redis.io
33
+ More credits available
34
+ = succeed '.' do
35
+ %a{ :href => '#' } here
36
+ .ncirl
37
+ %span National College of Ireland
38
+ %a{ :href => 'http://www.ncirl.ie/' }
39
+ %img{ :alt => 'National College of Ireland', :src => '/images/ncirl.png' }/
File without changes
@@ -0,0 +1,37 @@
1
+ module Cabalist
2
+ class ClassifierGenerator < Rails::Generators::NamedBase
3
+ desc <<-EOF
4
+ This generator creates a migration to add autoclassified_at attribute
5
+ to a chosen ActiveRecord model. The model name should be supplied as
6
+ and attrubute to the generator:
7
+ rails generate cabalist:classifier <ModelName>
8
+ EOF
9
+
10
+ include Rails::Generators::Migration
11
+
12
+ source_root File.expand_path('../templates/', __FILE__)
13
+ argument :name, :type => :string
14
+
15
+ def self.next_migration_number(dirname)
16
+ Time.now.strftime("%Y%m%d%H%M%S")
17
+ end
18
+
19
+ def create_migration
20
+ migration_template("migrations/add_cabalist.rb.erb",
21
+ "db/migrate/add_cabalist_to_#{name.tableize}.rb")
22
+ end
23
+
24
+ def add_to_gui_if_necessary
25
+ add_to_gui = ''
26
+ until %w(y Y n N).include?(add_to_gui)
27
+ add_to_gui = ask "Would you like to have access to this model through GUI dashboard? (Y/n) "
28
+ end
29
+ if %w(Y y).include?(add_to_gui)
30
+ inject_into_file "config/initializers/cabalist.rb",
31
+ "\n c.frontend_classes << #{name}",
32
+ :before => "\nend"
33
+ end
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,11 @@
1
+ class AddCabalistTo<%= name.pluralize %> < ActiveRecord::Migration
2
+
3
+ def up
4
+ add_column :<%= name.tableize %>, :autoclassified_at, :timestamp
5
+ end
6
+
7
+ def down
8
+ remove_column :<%= name.tableize %>, :autoclassified_at
9
+ end
10
+
11
+ end
File without changes
@@ -0,0 +1,26 @@
1
+ module Cabalist
2
+ class InstallGenerator < Rails::Generators::Base
3
+ desc <<-EOF
4
+ This generator installs the Cabalist initializer and
5
+ adds the route to Cabalist GUI (Cabalist::Frontend).
6
+ Usage:
7
+ rails generate cabalist:install <ModelName>
8
+ EOF
9
+
10
+ source_root File.expand_path('../templates/', __FILE__)
11
+
12
+ def copy_initializer
13
+ copy_file "initializers/cabalist.rb",
14
+ "config/initializers/cabalist.rb"
15
+ end
16
+
17
+ def copy_assets
18
+ directory "public/", "public/"
19
+ end
20
+
21
+ def add_route
22
+ route "match '/cabalist' => Cabalist::Frontend, :anchor => false, :as => :cabalist"
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,4 @@
1
+ # Setup your Cabalist installation
2
+ Cabalist.config do |c|
3
+ c.db_path = '/tmp/cabalist.db'
4
+ end
@@ -0,0 +1,23 @@
1
+ $(document).ready(function() {
2
+
3
+ $('img.show_icon').click(function() {
4
+ widget = $(this).parent().children('div.show_widget');
5
+ widget.css({ display: 'block' });
6
+ $(document).one('keydown', function(e) {
7
+ if (e.which == 27) widget.css({ display: 'none' });
8
+ });
9
+ });
10
+
11
+ $('img.edit_icon').click(function() {
12
+ widget = $(this).parent().children('div.edit_widget');
13
+ widget.css({ display: 'block' });
14
+ $(document).one('keydown', function(e) {
15
+ if (e.which == 27) widget.css({ display: 'none' });
16
+ });
17
+ });
18
+
19
+ $('img.close_icon').click(function() {
20
+ $(this).closest('div.overlay').css({ display: 'none' })
21
+ });
22
+
23
+ });
@@ -0,0 +1,197 @@
1
+ body {
2
+ background: #DDD;
3
+ font-family: "Helvetica Neue", sans-serif;
4
+ margin: 43px 0px 0px;
5
+ }
6
+
7
+ a { text-decoration: none; }
8
+ a:hover { text-decoration: underline; }
9
+
10
+ header {
11
+ background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #323232), color-stop(100%, #000000));
12
+ box-shadow: #999999 0px 4px 8px 0;
13
+ position: fixed;
14
+ width: 100%;
15
+ height: 43px;
16
+ top: 0;
17
+ left: 0;
18
+ padding: 0px 10px;
19
+ z-index: 1000;
20
+ }
21
+
22
+ header nav {
23
+ float: left;
24
+ border-left: 1px solid #323232;
25
+ padding: 4px 0px 4px 20px;
26
+ }
27
+ header img {
28
+ float: left;
29
+ padding: 4px 20px 4px 0px;
30
+ border-right: 1px solid black;
31
+ }
32
+ nav a {
33
+ font-size: 12px;
34
+ font-weight: bold;
35
+ line-height: 35px;
36
+ color: #ddd;
37
+ margin: 4px 0px;
38
+ padding-right: 20px;
39
+ text-shadow: black 0px 1px 1px;
40
+ }
41
+ header a:hover { color: white; }
42
+
43
+ .container {
44
+ margin: 0 auto;
45
+ max-width: 900px;
46
+ }
47
+ h1 { margin: .3em 0 .6em; }
48
+
49
+ .content {
50
+ background-color: #FAFAFA;
51
+ box-shadow: #cccccc 0px 0px 10px 0;
52
+ color: #333;
53
+ margin: 0 auto;
54
+ max-width: 880px;
55
+ padding: 10px 10px;
56
+ }
57
+
58
+ footer {
59
+ background: url(../images/symbol.png) no-repeat left top;
60
+ padding: 10px 10px 10px 62px;
61
+ max-width: 840px;
62
+ margin: 5px auto;
63
+ color: #777;
64
+ position: relative;
65
+ font-size: 11px;
66
+ }
67
+ footer a { color: rgb(110, 180, 30); }
68
+ footer p { width: 400px; margin-top: 0px; }
69
+ .ncirl {
70
+ position: absolute;
71
+ top: 0;
72
+ right: 0;
73
+ padding: 10px 10px;
74
+ }
75
+ .ncirl span { float: right; }
76
+ .ncirl img { float: right; clear: right; }
77
+
78
+ table.cabalist_records {
79
+ width: 100%;
80
+ border-collapse: collapse;
81
+ }
82
+
83
+ table.cabalist_records td {
84
+ border: 1px solid #CCC;
85
+ font-size: 80%;
86
+ padding: 0.4em 0.6em;
87
+ }
88
+
89
+ table.cabalist_records tr:nth-of-type(even) td {
90
+ background: #EEE;
91
+ }
92
+
93
+ table.cabalist_records thead td {
94
+ background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #DEDEDE), color-stop(100%, #CCC));
95
+ font-weight: bold;
96
+ text-shadow: white 0px 1px 1px;
97
+ }
98
+
99
+ ul.scopes {
100
+ background: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0%, #DEDEDE), color-stop(100%, #AAA));
101
+ font-size: 90%;
102
+ text-shadow: white 0px 1px 1px;
103
+ list-style-type: none;
104
+ margin: -10px -10px 10px -10px;
105
+ padding: 5px;
106
+ }
107
+
108
+ ul.scopes lh {
109
+ font-weight: bold;
110
+ }
111
+
112
+ ul.scopes li {
113
+ display: inline-block;
114
+ margin-left: 12px;
115
+ }
116
+
117
+ ul.scopes li a {
118
+ color: #333;
119
+ }
120
+
121
+ ul.scopes li a:hover {
122
+ color: white;
123
+ text-decoration: none;
124
+ text-shadow: #888 0px 1px 1px;
125
+ }
126
+
127
+ table.kaminari_nav {
128
+ width: 100%;
129
+ font-size: 80%;
130
+ }
131
+
132
+ table.kaminari_nav .next {
133
+ text-align: right;
134
+ }
135
+
136
+ pre {
137
+ margin: 0;
138
+ white-space: pre-wrap; /* css-3 */
139
+ white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
140
+ white-space: -pre-wrap; /* Opera 4-6 */
141
+ white-space: -o-pre-wrap; /* Opera 7 */
142
+ word-wrap: break-word; /* Internet Explorer 5.5+ */
143
+ }
144
+
145
+ .center {
146
+ text-align: center;
147
+ }
148
+
149
+ .overlay {
150
+ display: none;
151
+ background: rgba(0, 0, 0, 0.6);
152
+ position: absolute;
153
+ width: 100%;
154
+ height: 100%;
155
+ top: 0;
156
+ left: 0;
157
+ z-index: 1000;
158
+ }
159
+
160
+ .dialog-widget {
161
+ background: #FAFAFA;
162
+ border: 5px solid #DDD;
163
+ position: absolute;
164
+ left: 30%;
165
+ top: 100px;
166
+ padding: 20px;
167
+ width: 40%;
168
+ text-align: left;
169
+ }
170
+
171
+ .dialog-widget pre {
172
+ font-size: 1.2em;
173
+ }
174
+
175
+ .dialog-content {
176
+ position: relative;
177
+ }
178
+
179
+ p.label {
180
+ font-weight: bold;
181
+ margin: 0.3em;
182
+ }
183
+
184
+ .close_icon {
185
+ position: absolute;
186
+ right: -10px;
187
+ top: -10px;
188
+ }
189
+
190
+ form.autoclassify {
191
+ display: inline;
192
+ }
193
+
194
+ span.label_info {
195
+ display: inline-block;
196
+ width: 130px;
197
+ }