plotrb 0.0.1

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.
@@ -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