plotrb 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ module Plotrb
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,55 @@
1
+ module Plotrb
2
+
3
+ # The container for all visual elements.
4
+ # See {https://github.com/trifacta/vega/wiki/Visualization}
5
+ class Visualization
6
+
7
+ include ::Plotrb::Base
8
+ include ::Plotrb::Kernel
9
+
10
+ # @!attributes name
11
+ # @return [String] the name of the visualization
12
+ # @!attributes width
13
+ # @return [Integer] the total width of the data rectangle
14
+ # @!attributes height
15
+ # @return [Integer] the total height of the data rectangle
16
+ # @!attributes viewport
17
+ # @return [Array(Integer, Integer)] the width and height of the viewport
18
+ # @!attributes padding
19
+ # @return [Integer, Hash] the internal padding from the visualization
20
+ # @!attributes data
21
+ # @return [Array<Data>] the data for visualization
22
+ # @!attributes scales
23
+ # @return [Array<Scales>] the scales for visualization
24
+ # @!attributes marks
25
+ # @return [Array<Marks>] the marks for visualization
26
+ # @!attributes axes
27
+ # @return [Array<Axis>] the axes for visualization
28
+ # @!attributes legends
29
+ # @return [Array<Legend>] the legends for visualization
30
+ add_attributes :name, :width, :height, :viewport, :padding, :data, :scales,
31
+ :marks, :axes, :legends
32
+
33
+ def initialize(&block)
34
+ define_single_val_attributes(:name, :width, :height, :viewport, :padding)
35
+ define_multi_val_attributes(:data, :scales, :marks, :axes, :legends)
36
+ self.instance_eval(&block) if block_given?
37
+ end
38
+
39
+ def generate_spec(format=nil)
40
+ if format == :pretty
41
+ JSON.pretty_generate(self.collect_attributes)
42
+ else
43
+ JSON.generate(self.collect_attributes)
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def attribute_post_processing
50
+
51
+ end
52
+
53
+ end
54
+
55
+ end
@@ -0,0 +1,27 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'plotrb/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'plotrb'
7
+ spec.version = Plotrb::VERSION
8
+ spec.authors = ['Zuhao Wan']
9
+ spec.email = 'wanzuhao@gmail.com'
10
+ spec.description = %q{Plotrb is a plotting tool in Ruby.}
11
+ spec.summary = %q{Plotrb is a plotting tool in Ruby, built on Vega and D3, and is part of the SciRuby Project.}
12
+ spec.homepage = 'https://github.com/sciruby/plotrb'
13
+ spec.license = 'BSD 2-clause'
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = %w(lib)
19
+
20
+ spec.add_development_dependency 'bundler', '~> 1.3'
21
+ spec.add_development_dependency 'rake'
22
+ spec.add_development_dependency 'rspec'
23
+ spec.add_development_dependency 'yard'
24
+ spec.add_dependency 'yajl-ruby'
25
+ spec.add_dependency 'activemodel'
26
+ end
27
+
@@ -0,0 +1,227 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe 'Axis' do
4
+
5
+ subject { ::Plotrb::Axis.new(:x) }
6
+
7
+ describe '#type' do
8
+
9
+ it 'raises error if type is neither x or y' do
10
+ subject.instance_variable_set(:@type, :foo)
11
+ expect { subject.send(:process_type) }.to raise_error(ArgumentError)
12
+ end
13
+
14
+ end
15
+
16
+ describe '#scale' do
17
+
18
+ it 'sets the scale backing the axis by name' do
19
+ subject.from('foo_scale')
20
+ subject.scale.should == 'foo_scale'
21
+ end
22
+
23
+ it 'sets the scale backing the axis by the scale object' do
24
+ scale = ::Plotrb::Scale.new.name('foo_scale')
25
+ subject.from(scale)
26
+ subject.send(:process_scale)
27
+ subject.scale.should == 'foo_scale'
28
+ end
29
+
30
+ it 'raises error if scale is not found' do
31
+ subject.from('foo_scale')
32
+ ::Plotrb::Kernel.stub(:find_scale).and_return(nil)
33
+ expect { subject.send(:process_scale) }.to raise_error(ArgumentError)
34
+ end
35
+
36
+ end
37
+
38
+ describe '#orient' do
39
+
40
+ it 'sets the orient of the axis' do
41
+ subject.at_bottom
42
+ subject.orient.should == :bottom
43
+ end
44
+
45
+ end
46
+
47
+ describe '#title' do
48
+
49
+ it 'sets title of the axis' do
50
+ subject.title('foo')
51
+ subject.title.should == 'foo'
52
+ end
53
+
54
+ end
55
+
56
+ describe '#title_offset' do
57
+
58
+ it 'sets offset of the title' do
59
+ subject.offset_title_by(5)
60
+ subject.title_offset.should == 5
61
+ end
62
+
63
+ end
64
+
65
+ describe 'format' do
66
+
67
+ it 'accepts valid format specifier' do
68
+ subject.format('04d')
69
+ expect { subject.send(:process_format) }.to_not raise_error(ArgumentError)
70
+ end
71
+
72
+ it 'raises error if format specifier is invalid' do
73
+ subject.format('{$s04d,g')
74
+ expect { subject.send(:process_format) }.to raise_error(ArgumentError)
75
+ end
76
+
77
+ end
78
+
79
+ describe '#ticks' do
80
+
81
+ it 'sets ticks of the axis' do
82
+ subject.with_20_ticks
83
+ subject.ticks.should == 20
84
+ end
85
+
86
+ end
87
+
88
+ describe '#values' do
89
+
90
+ it 'sets values if given as an array' do
91
+ subject.values([1,2,3,4])
92
+ subject.values.should match_array([1,2,3,4])
93
+ end
94
+
95
+ it 'sets values if given one by one as arguments' do
96
+ subject.values(1,2,3,4)
97
+ subject.values.should match_array([1,2,3,4])
98
+ end
99
+
100
+ end
101
+
102
+ describe '#subdivide' do
103
+
104
+ it 'sets subdivide of the ticks' do
105
+ subject.subdivide_by(10)
106
+ subject.subdivide.should == 10
107
+ end
108
+
109
+ end
110
+
111
+ describe '#tick_padding' do
112
+
113
+ it 'sets padding for the ticks' do
114
+ subject.tick_padding(5)
115
+ subject.tick_padding.should == 5
116
+ end
117
+
118
+ end
119
+
120
+ describe '#tick_size' do
121
+
122
+ it 'sets size for the ticks' do
123
+ subject.tick_size(5)
124
+ subject.tick_size.should == 5
125
+ end
126
+
127
+ end
128
+
129
+ describe '#tick_size_major' do
130
+
131
+ it 'sets major tick size' do
132
+ subject.major_tick_size(10)
133
+ subject.tick_size_major.should == 10
134
+ end
135
+
136
+ end
137
+
138
+ describe '#tick_size_minor' do
139
+
140
+ it 'sets minor tick size' do
141
+ subject.minor_tick_size(10)
142
+ subject.tick_size_minor.should == 10
143
+ end
144
+
145
+ end
146
+
147
+ describe '#tick_size_end' do
148
+
149
+ it 'sets end tick size' do
150
+ subject.end_tick_size(10)
151
+ subject.tick_size_end.should == 10
152
+ end
153
+
154
+ end
155
+
156
+ describe '#offset' do
157
+
158
+ it 'sets offset of the axis' do
159
+ subject.offset_by(10)
160
+ subject.offset.should == 10
161
+ end
162
+
163
+ end
164
+
165
+ describe '#layer' do
166
+
167
+ it 'sets the layer of the axis' do
168
+ subject.in_front
169
+ subject.layer.should == :front
170
+ end
171
+
172
+ end
173
+
174
+ describe 'above' do
175
+
176
+ it 'sets the layer to front' do
177
+ subject.above
178
+ subject.layer.should == :front
179
+ subject.above?.should be_true
180
+ end
181
+
182
+ end
183
+
184
+ describe 'below' do
185
+
186
+ it 'sets the layer to back' do
187
+ subject.below
188
+ subject.layer.should == :back
189
+ subject.below?.should be_true
190
+ end
191
+
192
+ end
193
+
194
+ describe '#grid' do
195
+
196
+ it 'sets if grid-lines should be shown' do
197
+ subject.show_grid
198
+ subject.grid?.should be_true
199
+ end
200
+
201
+ end
202
+
203
+ describe '#method_missing' do
204
+
205
+ it 'sets ticks if in_some_ticks is called' do
206
+ subject.with_20_ticks
207
+ subject.ticks.should == 20
208
+ end
209
+
210
+ it 'sets subdivide if subdivide_by_some is called' do
211
+ subject.subdivide_by_10
212
+ subject.subdivide.should == 10
213
+ end
214
+
215
+ it 'sets orient if at_orient_position is called' do
216
+ subject.at_bottom
217
+ subject.orient.should == :bottom
218
+ end
219
+
220
+ it 'sets layer if at_layer_position is called' do
221
+ subject.in_front
222
+ subject.layer.should == :front
223
+ end
224
+
225
+ end
226
+
227
+ end
@@ -0,0 +1,321 @@
1
+ require_relative '../spec_helper'
2
+
3
+ describe 'Base' do
4
+
5
+ class FooClass
6
+ include ::Plotrb::Base
7
+ end
8
+
9
+ class BarClass
10
+ end
11
+
12
+ class BazClass
13
+ end
14
+
15
+ describe 'ClassMethods' do
16
+
17
+ let(:foo) { Class.new { include ::Plotrb::Base } }
18
+
19
+ describe '.attributes' do
20
+
21
+ it 'has attributes' do
22
+ foo.respond_to?(:attributes).should be_true
23
+ end
24
+
25
+ end
26
+
27
+ describe '.add_attributes' do
28
+
29
+ before(:each) do
30
+ foo.class_eval { add_attributes :foo_foo }
31
+ end
32
+
33
+ it 'keeps track of all attributes defined for class' do
34
+ foo.attributes.should match_array([:foo_foo])
35
+ end
36
+
37
+ it 'adds setter method for the attribute' do
38
+ bar = foo.new
39
+ bar.foo_foo = 1
40
+ bar.instance_variable_get(:@foo_foo).should == 1
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+
47
+ describe '#attributes' do
48
+
49
+ let(:foo) { FooClass.new }
50
+ before(:each) do
51
+ foo.singleton_class.class_eval { add_attributes :foo_foo }
52
+ end
53
+
54
+ it 'tracks both class-defined and instance-defined attributes' do
55
+ foo.add_attributes(:bar_bar)
56
+ foo.attributes.should match_array([:foo_foo, :bar_bar])
57
+ end
58
+
59
+ end
60
+
61
+ describe '#set_attribuets' do
62
+
63
+ let(:foo) { FooClass.new }
64
+
65
+ it 'creates attributes and sets values' do
66
+ foo.set_attributes(a: 1, b: 2)
67
+ foo.attributes.should match_array([:a, :b])
68
+ foo.instance_variable_get(:@a).should == 1
69
+ foo.instance_variable_get(:@b).should == 2
70
+ end
71
+
72
+ end
73
+
74
+ describe '#add_attributes' do
75
+
76
+ let(:foo) { FooClass.new }
77
+ let(:bar) { FooClass.new }
78
+ before(:each) do
79
+ FooClass.add_attributes(:foo_class)
80
+ end
81
+
82
+ it 'adds attributes to specific instance only' do
83
+ foo.add_attributes(:foo_foo)
84
+ bar.add_attributes(:bar_bar)
85
+ foo.attributes.should match_array([:foo_class, :foo_foo])
86
+ bar.attributes.should match_array([:foo_class, :bar_bar])
87
+ end
88
+
89
+ end
90
+
91
+ describe '#defined_attributes' do
92
+
93
+ let(:foo) { FooClass.new }
94
+
95
+ it 'only returns non-nil attributes' do
96
+ foo.set_attributes(a: 1, b: 2, c: nil)
97
+ foo.defined_attributes.should match_array([:a, :b])
98
+ end
99
+
100
+ end
101
+
102
+ describe '#collect_attributes' do
103
+
104
+ let(:foo) { FooClass.new }
105
+ let(:bar) { BarClass.new }
106
+ let(:baz) { BazClass.new }
107
+ before(:each) do
108
+ foo.add_attributes(:attr)
109
+ foo.stub(:attribute_post_processing)
110
+ end
111
+
112
+ it 'recursively collects attributes' do
113
+ BarClass.any_instance.stub(:respond_to?).with(:collect_attributes).
114
+ and_return(true)
115
+ BarClass.any_instance.stub(:collect_attributes).and_return('bar_values')
116
+ foo.attr = bar
117
+ foo.collect_attributes.should == { 'attr' => 'bar_values' }
118
+ end
119
+
120
+ it 'collects attributes of each of the array element' do
121
+ BarClass.any_instance.stub(:respond_to?).with(:collect_attributes).
122
+ and_return(true)
123
+ BazClass.any_instance.stub(:respond_to?).with(:collect_attributes).
124
+ and_return(true)
125
+ BarClass.any_instance.stub(:collect_attributes).and_return('bar_values')
126
+ BazClass.any_instance.stub(:collect_attributes).and_return('baz_values')
127
+ foo.attr = [bar, baz]
128
+ foo.collect_attributes.should == { 'attr' => %w(bar_values baz_values)}
129
+ end
130
+
131
+ end
132
+
133
+ describe '#define_boolean_attribute' do
134
+
135
+ let(:foo) { FooClass.new }
136
+
137
+ before(:each) do
138
+ foo.define_boolean_attribute(:bar)
139
+ end
140
+
141
+ it 'creates setter' do
142
+ foo.respond_to?(:bar).should be_true
143
+ end
144
+
145
+ it 'sets attribute to true when called' do
146
+ foo.bar
147
+ foo.instance_variable_get('@bar').should == true
148
+ end
149
+
150
+ it 'creates getter' do
151
+ foo.respond_to?(:bar?).should be_true
152
+ end
153
+
154
+ end
155
+
156
+ describe '#define_single_val_attribute' do
157
+
158
+ let(:foo) { FooClass.new }
159
+
160
+ context 'when no proc is provided' do
161
+
162
+ before(:each) do
163
+ foo.define_single_val_attribute(:bar)
164
+ end
165
+
166
+ it 'creates setter and getter' do
167
+ foo.respond_to?(:bar).should be_true
168
+ end
169
+
170
+ it 'acts as getter when no argument is provided' do
171
+ foo.should_receive(:instance_variable_get).with('@bar')
172
+ foo.bar
173
+ end
174
+
175
+ it 'sets value of the attribute if provided' do
176
+ foo.should_receive(:instance_variable_set).with('@bar', 1)
177
+ foo.bar(1)
178
+ end
179
+
180
+ it 'raises error if more than one value is given' do
181
+ expect { foo.bar(1,2,3) }.to raise_error(ArgumentError)
182
+ end
183
+
184
+ end
185
+
186
+ context 'when a proc is provided' do
187
+
188
+ it 'process the value before assigning to the attribute' do
189
+ p = lambda { |x| x + 1}
190
+ foo.define_single_val_attribute(:bar, p)
191
+ foo.bar(1)
192
+ foo.bar.should == 2
193
+ end
194
+
195
+ it 'raises error if condition check fails in proc' do
196
+ p = lambda { |x|
197
+ if x > 0
198
+ x + 1
199
+ else
200
+ raise ArgumentError
201
+ end
202
+ }
203
+ foo.define_single_val_attribute(:bar, p)
204
+ foo.bar(1)
205
+ foo.bar.should == 2
206
+ expect { foo.bar(0) }.to raise_error(ArgumentError)
207
+ end
208
+
209
+ end
210
+
211
+ end
212
+
213
+ describe '#define_multi_val_attribute' do
214
+
215
+ let(:foo) { FooClass.new }
216
+
217
+ context 'when no proc is provided' do
218
+
219
+ before(:each) do
220
+ foo.define_multi_val_attribute(:bar)
221
+ end
222
+
223
+ it 'creates setter and getter' do
224
+ foo.respond_to?(:bar).should be_true
225
+ end
226
+
227
+ it 'acts as getter when no argument is provided' do
228
+ foo.should_receive(:instance_variable_get).with('@bar')
229
+ foo.bar
230
+ end
231
+
232
+ it 'sets single value of the attribute if provided' do
233
+ foo.should_receive(:instance_variable_set).with('@bar', [1])
234
+ foo.bar(1)
235
+ end
236
+
237
+ it 'sets array of values' do
238
+ foo.should_receive(:instance_variable_set).with('@bar', [1, 2, 3])
239
+ foo.bar([1, 2, 3])
240
+ end
241
+
242
+ it 'sets multiple values' do
243
+ foo.should_receive(:instance_variable_set).with('@bar', [1, 2, 3])
244
+ foo.bar(1,2,3)
245
+ end
246
+
247
+ end
248
+
249
+ context 'when a proc is provided' do
250
+
251
+ it 'process the values before assigning to the attribute' do
252
+ p = lambda { |*x| x.each { |v| v + 1 } }
253
+ foo.define_multi_val_attribute(:bar, p)
254
+ foo.bar(1,2,3)
255
+ foo.bar.should == [1, 2, 3]
256
+ end
257
+
258
+ it 'is able to check argument size' do
259
+ p = lambda { |x, y, z| [x + 1, y + 1, z + 1] }
260
+ foo.define_multi_val_attribute(:bar, p)
261
+ foo.bar(1,2,3)
262
+ foo.bar.should == [2, 3, 4]
263
+ expect { foo.bar(1,2,3,4) }.to raise_error(ArgumentError)
264
+ end
265
+ end
266
+
267
+ end
268
+
269
+ describe '#classify' do
270
+
271
+ let(:foo) { Class.new { extend ::Plotrb::Base } }
272
+
273
+ it 'classifies string' do
274
+ foo.classify('visualization').should == 'Visualization'
275
+ end
276
+
277
+ it 'changes snake_case to CamelCase' do
278
+ foo.classify('foo_bar').should == 'FooBar'
279
+ end
280
+
281
+ it 'changes snake_case to camelCaseInJson' do
282
+ foo.classify('foo_bar_baz', :json).should == 'fooBarBaz'
283
+ end
284
+
285
+ end
286
+
287
+ describe 'Hash' do
288
+
289
+ describe '#reverse_merge' do
290
+
291
+ it 'should respond to reverse_merge' do
292
+ Hash.new.respond_to?(:reverse_merge).should be_true
293
+ end
294
+
295
+ it 'reverse merges hash' do
296
+ hash = {a: 1, b: 2}
297
+ default = {a:2, c:3}
298
+ hash.reverse_merge(default).should == {a: 1, b: 2, c: 3}
299
+ end
300
+
301
+ end
302
+
303
+ describe '#collect_attributes' do
304
+
305
+ it 'should respond to collect_attributes' do
306
+ Hash.new.respond_to?(:collect_attributes).should be_true
307
+ end
308
+
309
+ it 'recursively collects attributes' do
310
+ hash = {foo: FooClass.new, bar: BarClass.new}
311
+ FooClass.any_instance.stub(:collect_attributes).and_return('foo_value')
312
+ BarClass.any_instance.stub(:collect_attributes).and_return('bar_value')
313
+ hash.collect_attributes.should == {'foo' => 'foo_value',
314
+ 'bar' => 'bar_value'}
315
+ end
316
+
317
+ end
318
+
319
+ end
320
+
321
+ end