sinclair 1.14.2 → 1.15.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/sinclair.rb CHANGED
@@ -12,13 +12,13 @@ require 'active_support/core_ext'
12
12
  # class MyModel
13
13
  # end
14
14
  #
15
- # buider = Sinclair.new(MyModel)
16
- #
17
15
  # value = 10
18
- # builder.add_method(:default_value) { value }
19
- # builder.add_method(:value, '@value || default_value')
20
- # builder.add_method(:value=) { |val| @value = val }
21
- # builder.build
16
+ #
17
+ # Sinclair.build(MyModel) do
18
+ # add_method(:default_value) { value }
19
+ # add_method(:value, '@value || default_value')
20
+ # add_method(:value=) { |val| @value = val }
21
+ # end
22
22
  #
23
23
  # instance = MyModel.new
24
24
  # instance.value # returns 10
@@ -83,6 +83,7 @@ class Sinclair
83
83
  require 'sinclair/options_parser'
84
84
 
85
85
  autoload :VERSION, 'sinclair/version'
86
+ autoload :Caster, 'sinclair/caster'
86
87
  autoload :ClassMethods, 'sinclair/class_methods'
87
88
  autoload :Config, 'sinclair/config'
88
89
  autoload :ConfigBuilder, 'sinclair/config_builder'
@@ -104,6 +105,8 @@ class Sinclair
104
105
  extend ClassMethods
105
106
 
106
107
  # @method self.build(klass, options = {}, &block)
108
+ # @api public
109
+ #
107
110
  # Runs build using a block for adding the methods
108
111
  #
109
112
  # The block is executed adding the methods and after the builder
@@ -135,7 +138,6 @@ class Sinclair
135
138
  # builder = Sinclair.new(Purchase)
136
139
  #
137
140
  # @example Passing building options (Used on subclasses)
138
- #
139
141
  # class MyBuilder < Sinclair
140
142
  # def add_methods
141
143
  # if options_object.rescue_error
@@ -159,10 +161,9 @@ class Sinclair
159
161
  # class MyModel
160
162
  # end
161
163
  #
162
- # builder = MyBuilder.new(MyModel, rescue_error: true)
163
- #
164
- # builder.add_method
165
- # builder.build
164
+ # MyBuilder.build(MyModel, rescue_error: true) do
165
+ # add_method
166
+ # end
166
167
  #
167
168
  # instance = MyModel.new
168
169
  #
@@ -216,9 +217,9 @@ class Sinclair
216
217
  # end
217
218
  # end
218
219
  #
219
- # builder = Sinclair.new(Person)
220
- # builder.add_method(:full_name, '[first_name, last_name].join(" ")')
221
- # builder.build
220
+ # Sinclair.build(Person) do
221
+ # add_method(:full_name, '[first_name, last_name].join(" ")')
222
+ # end
222
223
  #
223
224
  # Person.new('john', 'wick').full_name # returns 'john wick'
224
225
  #
@@ -240,9 +241,9 @@ class Sinclair
240
241
  # end
241
242
  # end
242
243
  #
243
- # builder = Sinclair.new(Person)
244
- # builder.add_method(:bond_name) { "#{last_name}, #{first_name} #{last_name}" }
245
- # builder.build
244
+ # Sinclair.build(Person) do
245
+ # add_method(:bond_name) { "#{last_name}, #{first_name} #{last_name}" }
246
+ # end
246
247
  #
247
248
  # Person.new('john', 'wick').bond_name # returns 'wick, john wick'
248
249
  #
@@ -267,11 +268,11 @@ class Sinclair
267
268
  # end
268
269
  # end
269
270
  #
270
- # builder = Sinclair.new(Person)
271
- # builder.add_method(:bond_name, type: :block, cached: true) do
272
- # "{last_name}, #{first_name} #{last_name}"
271
+ # Sinclair.build(Person) do
272
+ # add_method(:bond_name, type: :block, cached: true) do
273
+ # "{last_name}, #{first_name} #{last_name}"
274
+ # end
273
275
  # end
274
- # builder.build
275
276
  #
276
277
  # person.Person.new('john', 'wick')
277
278
  #
@@ -9,9 +9,9 @@ describe Sinclair do
9
9
  klass = Class.new
10
10
  instance = klass.new
11
11
 
12
- builder = described_class.new(klass)
13
- builder.add_method(:random_number) { Random.rand(10..20) }
14
- builder.build
12
+ Sinclair.build(klass) do
13
+ add_method(:random_number) { Random.rand(10..20) }
14
+ end
15
15
 
16
16
  expect(instance.random_number).to be_between(10, 20)
17
17
  end
@@ -34,11 +34,11 @@ describe Sinclair do
34
34
  it 'adds the method' do
35
35
  klass = Class.new
36
36
 
37
- builder = described_class.new(klass)
38
- builder.add_class_method(
39
- :function, 'a ** b + c', parameters: [:a], named_parameters: [:b, { c: 15 }]
40
- )
41
- builder.build
37
+ Sinclair.build(klass) do
38
+ add_class_method(
39
+ :function, 'a ** b + c', parameters: [:a], named_parameters: [:b, { c: 15 }]
40
+ )
41
+ end
42
42
 
43
43
  expect(klass.function(10, b: 2)).to eq(115)
44
44
  end
@@ -4,23 +4,17 @@ require 'spec_helper'
4
4
 
5
5
  describe MyBuilder do
6
6
  describe '#yard' do
7
- subject(:builder) do
8
- described_class.new(klass, rescue_error: true)
9
- end
7
+ let(:klass) { Class.new }
10
8
 
11
- let(:klass) { Class.new }
12
- let(:instance) { klass.new }
9
+ describe 'Passing building options (Used on subclasses)' do
10
+ it 'builds the methods' do
11
+ MyBuilder.build(klass, rescue_error: true) do
12
+ add_methods
13
+ end
13
14
 
14
- describe '#build' do
15
- before do
16
- builder.add_methods
17
- builder.build
18
- end
15
+ instance = klass.new
19
16
 
20
- context 'when calling built method' do
21
- it 'returns default value' do
22
- expect(instance.symbolize).to eq(:default)
23
- end
17
+ expect(instance.symbolize).to eq(:default)
24
18
  end
25
19
  end
26
20
  end
@@ -7,9 +7,9 @@ describe 'yard Sinclair#add_method' do
7
7
  let(:klass) { Class.new(Person) }
8
8
 
9
9
  it 'creates new method' do
10
- builder = Sinclair.new(klass)
11
- builder.add_method(:full_name, '[first_name, last_name].join(" ")')
12
- builder.build
10
+ Sinclair.build(klass) do
11
+ add_method(:full_name, '[first_name, last_name].join(" ")')
12
+ end
13
13
 
14
14
  expect(klass.new('john', 'wick').full_name).to eq('john wick')
15
15
  end
@@ -19,9 +19,9 @@ describe 'yard Sinclair#add_method' do
19
19
  let(:klass) { Class.new(Person) }
20
20
 
21
21
  it 'creates new method' do
22
- builder = Sinclair.new(klass)
23
- builder.add_method(:bond_name) { "#{last_name}, #{first_name} #{last_name}" }
24
- builder.build
22
+ Sinclair.build(klass) do
23
+ add_method(:bond_name) { "#{last_name}, #{first_name} #{last_name}" }
24
+ end
25
25
 
26
26
  expect(klass.new('john', 'wick').bond_name).to eq('wick, john wick')
27
27
  end
@@ -31,11 +31,12 @@ describe 'yard Sinclair#add_method' do
31
31
  let(:klass) { Class.new(Person) }
32
32
 
33
33
  it 'creates new method' do
34
- builder = Sinclair.new(klass)
35
- builder.add_method(:bond_name, type: :block, cached: true) do
36
- "#{last_name}, #{first_name} #{last_name}"
34
+ Sinclair.build(klass) do
35
+ add_method(:bond_name, type: :block, cached: true) do
36
+ "#{last_name}, #{first_name} #{last_name}"
37
+ end
37
38
  end
38
- builder.build
39
+
39
40
  person = klass.new('john', 'wick')
40
41
 
41
42
  expect(person.bond_name).to eq('wick, john wick')
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: false
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'yard Sinclair::Caster' do
6
+ describe '.cast' do
7
+ it 'Casts with a symbol key' do
8
+ initial = Random.rand(10..20)
9
+ log = MathCaster.cast(initial, :log)
10
+ exp = MathCaster.cast(log, :exp)
11
+
12
+ expect(exp).to be_between(initial - 0.0001, initial + 0.0001)
13
+ end
14
+
15
+ it 'Casts passing parameter' do
16
+ base = Random.rand(3..6)
17
+ initial = Random.rand(10..20)
18
+ log = MathCaster.cast(initial, :log, base: base)
19
+ exp = MathCaster.cast(log, :exp, base: base)
20
+
21
+ expect(exp).to be_between(initial - 0.0001, initial + 0.0001)
22
+ end
23
+
24
+ it 'Casts with class key' do
25
+ hash = { a: 1, b: 2, 'c' => nil }
26
+ string = 'my string'
27
+ symbol = :the_symbol
28
+ number = 10
29
+ null = nil
30
+
31
+ code = <<-RUBY
32
+ hash_value = #{RubyStringCaster.to_ruby_string(hash)}
33
+ string_value = #{RubyStringCaster.to_ruby_string(string)}
34
+ symbol_value = #{RubyStringCaster.to_ruby_string(symbol)}
35
+ number = #{RubyStringCaster.to_ruby_string(number)}
36
+ null_value = #{RubyStringCaster.to_ruby_string(null)}
37
+ RUBY
38
+
39
+ expect(code).to eq(<<-RUBY)
40
+ hash_value = {:a=>1, :b=>2, "c"=>nil}
41
+ string_value = "my string"
42
+ symbol_value = :the_symbol
43
+ number = 10
44
+ null_value = nil
45
+ RUBY
46
+ end
47
+ end
48
+
49
+ describe '#cast' do
50
+ it 'Casts from a selected caster' do
51
+ caster = MathCaster.caster_for(:log)
52
+
53
+ expect(caster.cast(100)).to eq(2)
54
+ expect(caster.cast(8, base: 2)).to eq(3)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: false
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'yard Sinclair::Caster.cast_with' do
6
+ let(:my_caster) { Class.new(Sinclair::Caster) }
7
+
8
+ it 'Casting from pre registered symbol caster' do
9
+ my_caster.cast_with(:json, :to_json)
10
+
11
+ expect(my_caster.cast({ key: :value }, :json)).to eq('{"key":"value"}')
12
+ end
13
+
14
+ it 'Casting from pre registered block caster' do
15
+ my_caster.cast_with(:complex) do |hash|
16
+ real = hash[:real]
17
+ imaginary = hash[:imaginary]
18
+
19
+ "#{real.to_f} + #{imaginary.to_f} i"
20
+ end
21
+
22
+ value = { real: 10, imaginary: 5 }
23
+
24
+ expect(my_caster.cast(value, :complex)).to eq('10.0 + 5.0 i')
25
+ end
26
+
27
+ it 'Casting from pre registered class' do
28
+ my_caster.cast_with(Numeric, :to_i)
29
+
30
+ expect(my_caster.cast('10', Integer)).to eq(10)
31
+ end
32
+
33
+ it 'Casting from pre registered block caster from a class' do
34
+ my_caster.cast_with(HashModel) do |value, klass:|
35
+ klass.new(value)
36
+ end
37
+
38
+ my_caster.cast_with(String, &:to_json)
39
+
40
+ values = [
41
+ { klass: String, value: { name: 'john', age: 20, country: 'BR' } },
42
+ { klass: HashPerson, value: { name: 'Mary', age: 22, country: 'IT' } }
43
+ ]
44
+
45
+ values.map! do |config|
46
+ value = config[:value]
47
+ klass = config[:klass]
48
+ my_caster.cast(value, klass, klass: klass)
49
+ end
50
+
51
+ expect(values[0]).to eq('{"name":"john","age":20,"country":"BR"}')
52
+ expect(values[1]).to eq(HashPerson.new(name: 'Mary', age: 22))
53
+ end
54
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: false
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'yard Sinclair::Caster.cast' do
6
+ it 'Getting the caster with symbol key' do
7
+ expect(EnumConverter.to_array({ key: :value })).to eq([%i[key value]])
8
+ expect(EnumConverter.to_hash([%i[key value]])).to eq({ key: :value })
9
+ end
10
+
11
+ it 'Getting the caster with class key' do
12
+ expect(StringParser.cast('{"key":"value"}', JSON)).to eq({ 'key' => 'value' })
13
+ expect(StringParser.cast('10.2', Integer)).to eq(10)
14
+ expect(StringParser.cast('10.2', Float)).to eq(10.2)
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: false
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'yard Sinclair::Caster::ClassMethods' do
6
+ let(:my_caster) { Class.new(Sinclair::Caster) }
7
+
8
+ describe '.master_caster!' do
9
+ it 'Making a class to be a master caster' do
10
+ expect(my_caster.cast(10, :string)).to eq('10')
11
+
12
+ my_caster.master_caster!
13
+
14
+ expect(my_caster.cast(10, :string)).to eq(10)
15
+ end
16
+ end
17
+ end
@@ -5,16 +5,14 @@ require 'spec_helper'
5
5
  describe Sinclair::ConfigBuilder do
6
6
  describe 'yard' do
7
7
  describe '#instance_eval' do
8
- subject(:builder) do
9
- described_class.new(config, :name)
10
- end
8
+ it 'sets variable from config' do
9
+ config = MyConfig.new
11
10
 
12
- let(:config) { MyConfig.new }
11
+ builder = described_class.new(config, :name)
13
12
 
14
- it 'sets variable from config' do
15
- expect { builder.instance_eval { |c| c.name 'John' } }
16
- .to change(config, :name)
17
- .from(nil).to('John')
13
+ builder.instance_eval { |c| c.name 'John' }
14
+
15
+ expect(config.name).to eq('John')
18
16
  end
19
17
  end
20
18
  end
@@ -5,33 +5,19 @@ require 'spec_helper'
5
5
  describe Sinclair::ConfigClass do
6
6
  describe 'yard' do
7
7
  describe '.add_configs' do
8
- subject(:config) { AppConfig.new }
8
+ it 'Adding configurations to config class' do
9
+ config = AppConfig.new
9
10
 
10
- it 'has a secret configuration method' do
11
11
  expect(config.secret).to be_nil
12
- end
13
-
14
- it 'has a app_name configuration method' do
15
12
  expect(config.app_name).to eq('MyApp')
16
- end
17
-
18
- context 'when configured' do
19
- let(:config_builder) do
20
- Sinclair::ConfigBuilder.new(config)
21
- end
22
13
 
23
- before do
24
- config_builder.secret '123abc'
25
- config_builder.app_name 'MySuperApp'
26
- end
14
+ config_builder = Sinclair::ConfigBuilder.new(config)
27
15
 
28
- it 'has a secret configuration method' do
29
- expect(config.secret).to eq('123abc')
30
- end
16
+ config_builder.secret '123abc'
17
+ config_builder.app_name 'MySuperApp'
31
18
 
32
- it 'has a app_name configuration method' do
33
- expect(config.app_name).to eq('MySuperApp')
34
- end
19
+ expect(config.secret).to eq('123abc')
20
+ expect(config.app_name).to eq('MySuperApp')
35
21
  end
36
22
  end
37
23
  end
@@ -4,10 +4,8 @@ require 'spec_helper'
4
4
 
5
5
  describe Sinclair do
6
6
  describe 'yard' do
7
- let(:klass) { Class.new(MyModel) }
8
- let(:instance) { klass.new }
9
- let(:builder) { described_class.new(klass) }
10
- let(:default_value) { 10 }
7
+ let(:klass) { Class.new(MyModel) }
8
+ let(:builder) { described_class.new(klass) }
11
9
 
12
10
  describe 'Using cache' do
13
11
  subject(:server) { Server.new }
@@ -85,38 +83,21 @@ describe Sinclair do
85
83
  end
86
84
  end
87
85
 
88
- describe '#build' do
89
- before do
90
- value = default_value
91
- builder.add_method(:default_value) { value }
92
- builder.add_method(:value, '@value || default_value')
93
- builder.add_method(:value=) { |val| @value = val }
94
- end
95
-
96
- describe 'after the build' do
97
- before { builder.build }
86
+ describe 'Stand alone usage' do
87
+ it 'builds the methods' do
88
+ value = 10
98
89
 
99
- it 'creates the expected methods' do
100
- expect(instance.value).to eq(10)
90
+ Sinclair.build(klass) do
91
+ add_method(:default_value) { value }
92
+ add_method(:value, '@value || default_value')
93
+ add_method(:value=) { |val| @value = val }
101
94
  end
102
95
 
103
- context 'when default value is overwritten' do
104
- before do
105
- instance.value = 20
106
- end
96
+ instance = klass.new
107
97
 
108
- it 'returns the new written value' do
109
- expect(instance.value).to eq(20)
110
- end
111
- end
112
- end
113
-
114
- context 'when calling the build' do
115
- it do
116
- expect do
117
- builder.build
118
- end.to change { instance.respond_to?(:default_value) }.to(true)
119
- end
98
+ expect(instance.value).to eq(10)
99
+ instance.value = 20
100
+ expect(instance.value).to eq(20)
120
101
  end
121
102
  end
122
103
  end
@@ -0,0 +1,186 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::Caster::ClassMethods do
6
+ subject(:caster) { Class.new(Sinclair::Caster) }
7
+
8
+ describe '.cast_with' do
9
+ let(:value) { instance_double('value', to_p: final_value) }
10
+ let(:final_value) { Random.rand(100) }
11
+
12
+ context 'when a proc is given' do
13
+ it do
14
+ expect { caster.cast_with(:problem, &:to_p) }
15
+ .not_to raise_error
16
+ end
17
+
18
+ context 'when casting is called' do
19
+ before { caster.cast_with(:problem, &:to_p) }
20
+
21
+ it 'returns the cast value' do
22
+ expect(caster.cast(value, :problem)).to eq(final_value)
23
+ end
24
+ end
25
+ end
26
+
27
+ context 'when a proc with two arguments is given' do
28
+ it do
29
+ expect { caster.cast_with(:problem) { |v, **_opts| v.to_p } }
30
+ .not_to raise_error
31
+ end
32
+
33
+ context 'when casting is called' do
34
+ before { caster.cast_with(:problem) { |v, sum:| v.to_p + sum } }
35
+
36
+ it 'returns the cast value' do
37
+ expect(caster.cast(value, :problem, sum: 2))
38
+ .to eq(final_value + 2)
39
+ end
40
+ end
41
+ end
42
+
43
+ context 'when a symbol is given' do
44
+ let(:instance) { Sinclair::Caster.new(&:to_p) }
45
+
46
+ it do
47
+ expect { caster.cast_with(:problem, instance) }
48
+ .not_to raise_error
49
+ end
50
+
51
+ context 'when casting is called' do
52
+ before { caster.cast_with(:problem, instance) }
53
+
54
+ it 'returns the cast value' do
55
+ expect(caster.cast(value, :problem)).to eq(final_value)
56
+ end
57
+ end
58
+ end
59
+
60
+ context 'when a caster is given is given' do
61
+ it do
62
+ expect { caster.cast_with(:problem, :to_p) }
63
+ .not_to raise_error
64
+ end
65
+
66
+ context 'when casting is called' do
67
+ before { caster.cast_with(:problem, :to_p) }
68
+
69
+ it 'returns the cast value' do
70
+ expect(caster.cast(value, :problem)).to eq(final_value)
71
+ end
72
+ end
73
+ end
74
+
75
+ context 'when key is a class' do
76
+ it do
77
+ expect { caster.cast_with(Integer, :to_i) }
78
+ .not_to raise_error
79
+ end
80
+
81
+ context 'when casting is called' do
82
+ before { caster.cast_with(Integer, :to_i) }
83
+
84
+ it 'returns the cast value' do
85
+ expect(caster.cast('10', Integer)).to eq(10)
86
+ end
87
+ end
88
+ end
89
+
90
+ context 'when key is a module' do
91
+ it do
92
+ expect { caster.cast_with(JSON) { |value| JSON.parse(value) } }
93
+ .not_to raise_error
94
+ end
95
+
96
+ context 'when casting is called' do
97
+ before { caster.cast_with(JSON) { |value| JSON.parse(value) } }
98
+
99
+ it 'returns the cast value' do
100
+ expect(caster.cast('{"key":"value"}', JSON))
101
+ .to eq({ 'key' => 'value' })
102
+ end
103
+ end
104
+ end
105
+
106
+ context 'when key is a superclass' do
107
+ it do
108
+ expect { caster.cast_with(Numeric, :to_i) }
109
+ .not_to raise_error
110
+ end
111
+
112
+ context 'when casting is called with the child class' do
113
+ before { caster.cast_with(Numeric, :to_i) }
114
+
115
+ it 'returns the cast value' do
116
+ expect(caster.cast('10', Integer)).to eq(10)
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ describe '.caster_for' do
123
+ context 'when the key has been defined with a symbol key' do
124
+ before { caster.cast_with(:problem, :to_p) }
125
+
126
+ it do
127
+ expect(caster.caster_for(:problem))
128
+ .to be_a(Sinclair::Caster)
129
+ end
130
+ end
131
+
132
+ context 'when the key has not been defined' do
133
+ it do
134
+ expect(caster.caster_for(:problem))
135
+ .to be_a(Sinclair::Caster)
136
+ end
137
+ end
138
+ end
139
+
140
+ describe '.cast' do
141
+ let(:value) { values.sample }
142
+ let(:values) do
143
+ [Random.rand, 'some string', { key: 10 }, Object.new, Class.new, [2, 3]]
144
+ end
145
+
146
+ context 'when klass is nil' do
147
+ it 'returns the value' do
148
+ expect(caster.cast(value, nil))
149
+ .to eq(value)
150
+ end
151
+ end
152
+
153
+ context 'when class is :string' do
154
+ it 'returns the value as string' do
155
+ expect(caster.cast(value, :string))
156
+ .to eq(value.to_s)
157
+ end
158
+ end
159
+
160
+ context 'when class is :integer' do
161
+ let(:value) { '10.5' }
162
+
163
+ it 'returns the value as integer' do
164
+ expect(caster.cast(value, :integer))
165
+ .to eq(10)
166
+ end
167
+ end
168
+
169
+ context 'when class is :float' do
170
+ let(:value) { '10.5' }
171
+
172
+ it 'returns the value as float' do
173
+ expect(caster.cast(value, :float))
174
+ .to eq(10.5)
175
+ end
176
+ end
177
+ end
178
+
179
+ describe '.master_caster!' do
180
+ it 'ignores superclass registered casters' do
181
+ expect { caster.master_caster! }
182
+ .to change { caster.cast('10', :integer) }
183
+ .from(10).to('10')
184
+ end
185
+ end
186
+ end