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.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +1 -0
- data/.travis.yml +3 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +38 -0
- data/README.rdoc +77 -0
- data/Rakefile +7 -0
- data/examples/arc.rb +31 -0
- data/examples/area.rb +48 -0
- data/examples/bar.rb +44 -0
- data/examples/barley.rb +66 -0
- data/examples/choropleth.rb +48 -0
- data/examples/lifelines.rb +106 -0
- data/examples/scatter.rb +43 -0
- data/lib/plotrb.rb +25 -0
- data/lib/plotrb/axes.rb +208 -0
- data/lib/plotrb/base.rb +193 -0
- data/lib/plotrb/data.rb +232 -0
- data/lib/plotrb/kernel.rb +136 -0
- data/lib/plotrb/legends.rb +168 -0
- data/lib/plotrb/marks.rb +459 -0
- data/lib/plotrb/scales.rb +346 -0
- data/lib/plotrb/simple.rb +197 -0
- data/lib/plotrb/transforms.rb +592 -0
- data/lib/plotrb/version.rb +3 -0
- data/lib/plotrb/visualization.rb +55 -0
- data/plotrb.gemspec +27 -0
- data/spec/plotrb/axes_spec.rb +227 -0
- data/spec/plotrb/base_spec.rb +321 -0
- data/spec/plotrb/data_spec.rb +258 -0
- data/spec/plotrb/kernel_spec.rb +54 -0
- data/spec/plotrb/legends_spec.rb +157 -0
- data/spec/plotrb/marks_spec.rb +46 -0
- data/spec/plotrb/scales_spec.rb +187 -0
- data/spec/plotrb/simple_spec.rb +61 -0
- data/spec/plotrb/transforms_spec.rb +248 -0
- data/spec/plotrb/visualization_spec.rb +93 -0
- data/spec/plotrb_spec.rb +5 -0
- data/spec/spec_helper.rb +12 -0
- metadata +180 -0
@@ -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
|
data/plotrb.gemspec
ADDED
@@ -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
|