sinclair 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b59fc038965ca4d716620bcdba5e7cb3eb250b6d
4
- data.tar.gz: 060a5b3eaf6b829a4b3cd97acdf6465cab863e06
3
+ metadata.gz: e2734e2007f6c98dc270ea39df18e07aed7f9324
4
+ data.tar.gz: d570bf309c48f65b080b0db7da0301968fb055c4
5
5
  SHA512:
6
- metadata.gz: 1846ce94184b85e892a2c3ec24c5420f159bcf330b377d0f4694cb4e5c06779fd4d03cc35bed5967a7799761408416c76d6b82eae270e5b105c3e941634f9c95
7
- data.tar.gz: 0e348b3209b78b692d9a98f6badf4f77a4e52f27e230f24b7d6257dd326be20ce64f0c9a6aa33cfcdc8ff32007e86047bbe8354dbc09e37cf4bb73c163a0d76e
6
+ metadata.gz: 4cbe6a2654818eedc3aac238d6689e61210d1e2fe9ad1dfc892bc340474b9ccc49a1474a2fa4e69dabf3dd3975ddc003120cc2a7db31c4a32b74ea3b55fc8924
7
+ data.tar.gz: daf0ff8fbe75d336c0651dc27298b530a12b1c2709e67b3a6b2dd3c64407a5ddbb1ff14d0a92dd018a3df4f1f143508c0812e4075f4317a0f2105b214dc01f49
data/.gitignore CHANGED
@@ -2,3 +2,5 @@ coverages
2
2
  pkg
3
3
  Gemfile.lock
4
4
  coverage
5
+ doc
6
+ .yardoc/
data/.rubocop_todo.yml CHANGED
@@ -111,8 +111,6 @@ Metrics/BlockLength:
111
111
  # SupportedStyles: nested, compact
112
112
  Style/ClassAndModuleChildren:
113
113
  Exclude:
114
- - 'lib/sinclair/method_definition.rb'
115
- - 'lib/sinclair/options_parser.rb'
116
114
  - 'spec/support/models/dummy_builder.rb'
117
115
  - 'spec/support/models/dummy_options_parser.rb'
118
116
 
data/README.md CHANGED
@@ -33,34 +33,38 @@ The concern builder can actully be used in two ways, as an stand alone object ca
33
33
  adding methods to your class or by extending it for more complex logics
34
34
 
35
35
  - Stand Alone usage:
36
- ```ruby
37
- class Clazz
38
- end
39
36
 
40
- builder = Sinclair.new(Clazz)
37
+ ```ruby
41
38
 
42
- builder.add_method(:twenty, '10 + 10')
43
- builder.add_method(:eighty) { 4 * twenty }
44
- builder.build
39
+ class Clazz
40
+ end
45
41
 
46
- instance = Clazz.new
42
+ builder = Sinclair.new(Clazz)
47
43
 
48
- puts "Twenty => #{instance.twenty}"
49
- puts "Eighty => #{instance.eighty}"
50
- ```
44
+ builder.add_method(:twenty, '10 + 10')
45
+ builder.add_method(:eighty) { 4 * twenty }
46
+ builder.build
51
47
 
52
- ```string
53
- Twenty => 20
54
- Eighty => 80
55
- ```
48
+ instance = Clazz.new
49
+
50
+ puts "Twenty => #{instance.twenty}"
51
+ puts "Eighty => #{instance.eighty}"
52
+ ```
53
+
54
+ ```string
55
+
56
+ Twenty => 20
57
+ Eighty => 80
58
+ ```
56
59
 
57
60
  - Extending the builder
58
61
 
59
62
  ```ruby
63
+
60
64
  class ValidationBuilder < Sinclair
61
65
  delegate :expected, to: :options_object
62
66
 
63
- def initialize(clazz, options={})
67
+ def initialize(klass, options={})
64
68
  super
65
69
  end
66
70
 
@@ -69,7 +73,7 @@ adding methods to your class or by extending it for more complex logics
69
73
  end
70
74
 
71
75
  def add_accessors(fields)
72
- clazz.send(:attr_accessor, *fields)
76
+ klass.send(:attr_accessor, *fields)
73
77
  end
74
78
  end
75
79
 
@@ -119,42 +123,32 @@ adding methods to your class or by extending it for more complex logics
119
123
  ```
120
124
 
121
125
  the instance will respond to the methods
122
- ```name``` ```name=``` ```name_valid?```
123
- ```surname``` ```surname=``` ```surname_valid?```
124
- ```age``` ```age=``` ```age_valid?```
125
- ```legs``` ```legs=``` ```legs_valid?```
126
- ```valid?```
126
+ ```name``` ```name=``` ```name_valid?```
127
+ ```surname``` ```surname=``` ```surname_valid?```
128
+ ```age``` ```age=``` ```age_valid?```
129
+ ```legs``` ```legs=``` ```legs_valid?```
130
+ ```valid?```
127
131
 
128
132
  ```ruby
133
+
129
134
  valid_object = MyClass.new(
130
135
  name: :name,
131
136
  surname: 'surname',
132
137
  age: 20,
133
138
  legs: 2
134
139
  )
135
- valid_object.valid?
136
- ```
137
-
138
- returns
139
-
140
- ```
141
- true
140
+ valid_object.valid? # returns true
142
141
  ```
143
142
 
144
143
  ```ruby
144
+
145
145
  invalid_object = MyClass.new(
146
146
  name: 'name',
147
147
  surname: 'surname',
148
148
  age: 20,
149
149
  legs: 2
150
150
  )
151
- invalid_object.valid?
152
- ```
153
-
154
- returns
155
-
156
- ```
157
- false
151
+ invalid_object.valid? # returns false
158
152
  ```
159
153
 
160
154
  RSspec matcher
@@ -162,64 +156,67 @@ RSspec matcher
162
156
 
163
157
  You can use the provided matcher to check that your builder is adding a method correctly
164
158
 
165
- ```ruby
166
- class DefaultValue
167
- delegate :build, to: :builder
168
- attr_reader :klass, :method, :value
159
+ ```ruby
169
160
 
170
- def initialize(klass, method, value)
171
- @klass = klass
172
- @method = method
173
- @value = value
174
- end
161
+ class DefaultValue
162
+ delegate :build, to: :builder
163
+ attr_reader :klass, :method, :value
164
+
165
+ def initialize(klass, method, value)
166
+ @klass = klass
167
+ @method = method
168
+ @value = value
169
+ end
175
170
 
176
- private
171
+ private
177
172
 
178
- def builder
179
- @builder ||= Sinclair.new(klass).tap do |b|
180
- b.add_method(method) { value }
173
+ def builder
174
+ @builder ||= Sinclair.new(klass).tap do |b|
175
+ b.add_method(method) { value }
176
+ end
181
177
  end
182
178
  end
183
- end
184
-
185
- RSpec.configure do |config|
186
- config.include Sinclair::Matchers
187
- end
188
-
189
- RSpec.describe DefaultValue do
190
- let(:klass) { Class.new }
191
- let(:method) { :the_method }
192
- let(:value) { Random.rand(100) }
193
- let(:builder) { described_class.new(klass, method, value) }
194
- let(:instance) { klass.new }
195
-
196
- context 'when the builder runs' do
197
- it do
198
- expect do
199
- described_class.new(klass, method, value).build
200
- end.to add_method(method).to(instance)
201
- end
179
+
180
+ RSpec.configure do |config|
181
+ config.include Sinclair::Matchers
202
182
  end
203
183
 
204
- context 'when the builder runs' do
205
- it do
206
- expect do
207
- described_class.new(klass, method, value).build
208
- end.to add_method(method).to(klass)
184
+ RSpec.describe DefaultValue do
185
+ let(:klass) { Class.new }
186
+ let(:method) { :the_method }
187
+ let(:value) { Random.rand(100) }
188
+ let(:builder) { described_class.new(klass, method, value) }
189
+ let(:instance) { klass.new }
190
+
191
+ context 'when the builder runs' do
192
+ it do
193
+ expect do
194
+ described_class.new(klass, method, value).build
195
+ end.to add_method(method).to(instance)
196
+ end
197
+ end
198
+
199
+ context 'when the builder runs' do
200
+ it do
201
+ expect do
202
+ described_class.new(klass, method, value).build
203
+ end.to add_method(method).to(klass)
204
+ end
209
205
  end
210
206
  end
211
- end
212
- ```
207
+ ```
213
208
 
214
- ```bash
215
- > bundle exec rspec
216
- ```
209
+ ```bash
217
210
 
218
- ```string
219
- DefaultValue
220
- when the builder runs
221
- should add method 'the_method' to #<Class:0x0000000146c160> instances
222
- when the builder runs
223
- should add method 'the_method' to #<Class:0x0000000143a1b0> instances
211
+ > bundle exec rspec
212
+ ```
213
+
214
+ ```string
224
215
 
225
- ```
216
+ DefaultValue
217
+ when the builder runs
218
+ should add method 'the_method' to #<Class:0x0000000146c160> instances
219
+ when the builder runs
220
+ should add method 'the_method' to #<Class:0x0000000143a1b0> instances
221
+
222
+ ```
data/lib/sinclair.rb CHANGED
@@ -1,6 +1,25 @@
1
1
  require 'active_support'
2
2
  require 'active_support/all'
3
3
 
4
+ # Builder that add instance methods to a class
5
+ #
6
+ # @example
7
+ #
8
+ # class MyModel
9
+ # end
10
+ #
11
+ # buider = Sinclair.new(MyModel)
12
+ #
13
+ # value = 10
14
+ # builder.add_method(:default_value) { value }
15
+ # builder.add_method(:value, '@value || default_value')
16
+ # builder.add_method(:value=) { |val| @value = val }
17
+ # builder.build
18
+ #
19
+ # instance = MyModel.new
20
+ # instance.value # returns 10
21
+ # instance.value = 20
22
+ # instance.value # returns 20
4
23
  class Sinclair
5
24
  require 'sinclair/options_parser'
6
25
 
@@ -10,29 +29,166 @@ class Sinclair
10
29
 
11
30
  include OptionsParser
12
31
 
13
- attr_reader :clazz
14
-
15
- def initialize(clazz, options = {})
16
- @clazz = clazz
32
+ # @param klass [Class] to receive the methods
33
+ # @param options [Hash] open hash options to be used by builders inheriting from Sinclair
34
+ # through the Sinclair::OptionsParser concern
35
+ #
36
+ # @example
37
+ #
38
+ # class Purchase
39
+ # def initialize(value, quantity)
40
+ # @value = value
41
+ # @quantity = quantity
42
+ # end
43
+ # end
44
+ #
45
+ # builder = Sinclair.new(Purchase)
46
+ #
47
+ # @example
48
+ #
49
+ # builder = Sinclair.new(Purchase, rescue_error: true)
50
+ def initialize(klass, options = {})
51
+ @klass = klass
17
52
  @options = options
18
53
  end
19
54
 
55
+ # builds all the methods added into the klass
56
+ #
57
+ # @example
58
+ #
59
+ # class MyModel
60
+ # end
61
+ #
62
+ # buider = Sinclair.new(MyModel)
63
+ #
64
+ # builder.add_method(:default_value) { value }
65
+ #
66
+ # MyModel.new.respond_to(:default_value) # returns false
67
+ #
68
+ # builder.build
69
+ #
70
+ # MyModel.new.respond_to(:default_value) # returns true
20
71
  def build
21
72
  definitions.each do |definition|
22
- definition.build(clazz)
73
+ definition.build(klass)
23
74
  end
24
75
  end
25
76
 
77
+ # add a method to the method list to be created on klass
78
+ #
79
+ # @overload add_method(name, code)
80
+ # @param name [String/Symbol] name of the method to be added
81
+ # @param code [String] code to be evaluated when the method is ran
82
+ #
83
+ # @example
84
+ # class Person
85
+ # attr_reader :first_name, :last_name
86
+ #
87
+ # def initialize(first_name, last_name)
88
+ # @first_name = first_name
89
+ # @last_name = last_name
90
+ # end
91
+ # end
92
+ #
93
+ # builder = Sinclair.new(Person)
94
+ # builder.add_method(:full_name, '[first_name, last_name].join(" ")')
95
+ # builder.build
96
+ #
97
+ # Person.new('john', 'wick').full_name # returns 'john wick'
98
+ #
99
+ # @overload add_method(name, &block)
100
+ # @param name [String/Symbol] name of the method to be added
101
+ # @param block [Proc] block to be ran as method
102
+ #
103
+ # @example
104
+ #
105
+ # builder = Sinclair.new(Person)
106
+ # builder.add_method(:bond_name) { "#{last_name}, #{full_name}" }
107
+ # builder.build
108
+ #
109
+ # Person.new('john', 'wick').bond_name # returns 'wick, john wick'
26
110
  def add_method(name, code = nil, &block)
27
111
  definitions << MethodDefinition.new(name, code, &block)
28
112
  end
29
113
 
114
+ # evaluetes a block which will result in a [String] to be
115
+ # then used as code for the method
116
+ #
117
+ # @example
118
+ #
119
+ # module InitialValuer
120
+ # extend ActiveSupport::Concern
121
+ #
122
+ # class_methods do
123
+ # def initial_value_for(attribute, value)
124
+ # builder = Sinclair.new(self, initial_value: value)
125
+ # builder.eval_and_add_method(attribute) do
126
+ # "@#{attribute} ||= #{options_object.initial_value}"
127
+ # end
128
+ # builder.build
129
+ # end
130
+ # end
131
+ # end
132
+ #
133
+ # class MyClass
134
+ # include InitialValuer
135
+ # attr_writer :age
136
+ # initial_value_for :age, 20
137
+ # end
138
+ #
139
+ # object = MyClass.new
140
+ # object.age # 20
141
+ # object.age = 30
142
+ # object.age # 30
143
+ #
144
+ # @example
145
+ #
146
+ # class Purchase
147
+ # def initialize(value, quantity)
148
+ # @value = value
149
+ # @quantity = quantity
150
+ # end
151
+ # end
152
+ #
153
+ # builder = Sinclair.new(Purchase)
154
+ #
155
+ # builder.eval_and_add_method(:total_price) do
156
+ # code = 'self.value * self.quantity'
157
+ # code.concat ' rescue 0' if options_object.rescue_error
158
+ # code
159
+ # end
160
+ #
161
+ # builder.build
162
+ #
163
+ # Purchase.new(2.3, 5).total_price # raises error
164
+ #
165
+ # @example
166
+ #
167
+ # builder = Sinclair.new(Purchase, rescue_error: true)
168
+ #
169
+ # builder.eval_and_add_method(:total_price) do
170
+ # code = 'self.value * self.quantity'
171
+ # code.concat ' rescue 0' if options_object.rescue_error
172
+ # code
173
+ # end
174
+ #
175
+ # builder.build
176
+ #
177
+ # Purchase.new(2.3, 5).total_price # returns 0
178
+ #
179
+ # class Purchase
180
+ # attr_reader :value, :quantity
181
+ # end
182
+ #
183
+ # Purchase.new(2.3, 5).total_price # returns 11.5
30
184
  def eval_and_add_method(name, &block)
31
185
  add_method(name, instance_eval(&block))
32
186
  end
33
187
 
34
188
  private
35
189
 
190
+ attr_reader :klass
191
+
36
192
  def definitions
37
193
  @definitions ||= []
38
194
  end
@@ -1,8 +1,33 @@
1
1
  class Sinclair
2
+ # Matchers module will have the DSL to be included in RSpec in order to have
3
+ # access to the matchers
4
+ #
5
+ # @example
6
+ # RSpec.configure do |config|
7
+ # config.include Sinclair::Matchers
8
+ # end
9
+ #
10
+ # class MyModel
11
+ # end
12
+ #
13
+ # RSpec.describe 'my test' do
14
+ # let(:klass) { Class.new(MyModel) }
15
+ # let(:builder) { Sinclair.new(klass) }
16
+ #
17
+ # before do
18
+ # builder.add_method(:class_name, 'self.class.name')
19
+ # end
20
+ #
21
+ # it do
22
+ # expect { builder.build }.to add_method(:class_name).to(klass)
23
+ # end
24
+ # end
2
25
  module Matchers
3
26
  autoload :AddMethod, 'sinclair/matchers/add_method'
4
27
  autoload :AddMethodTo, 'sinclair/matchers/add_method_to'
5
28
 
29
+ # DSL to AddMethod
30
+ # @return [AddMethod] RSpec Matcher
6
31
  def add_method(method)
7
32
  Sinclair::Matchers::AddMethod.new(method)
8
33
  end
@@ -1,19 +1,29 @@
1
1
  class Sinclair
2
2
  module Matchers
3
+ # AddMethod is able to build an instance of Sinclair::Matchers::AddMethodTo
3
4
  class AddMethod < RSpec::Matchers::BuiltIn::BaseMatcher
4
- attr_reader :method
5
-
5
+ # as any matcher is expected to implement matches?, we raise a warning on the usage as
6
+ # this is only a builder for AddMethodTo
6
7
  def matches?(_actual)
7
8
  raise SyntaxError, 'You should specify which instance the method is being added to' \
8
9
  "add_method(:#{method}).to(instance)"
9
10
  end
10
11
 
11
- def initialize(method = nil)
12
+ # @param method [String/Symbol] the method, to be checked, name
13
+ def initialize(method)
12
14
  @method = method
13
15
  end
14
16
 
15
- def to(instance = nil)
16
- AddMethodTo.new(instance, method)
17
+ # @return [AddMethodTo] the correct matcher
18
+ # @overload to(klass)
19
+ # @param [Class] klass
20
+ # class where the method should be added to
21
+ #
22
+ # @overload to(instance)
23
+ # @param [Object] instance
24
+ # instance of the class where the method should be added to
25
+ def to(target = nil)
26
+ AddMethodTo.new(target, method)
17
27
  end
18
28
 
19
29
  def equal?(other)
@@ -21,9 +31,14 @@ class Sinclair
21
31
  other.method == method
22
32
  end
23
33
 
34
+ # definition needed for block matchers
24
35
  def supports_block_expectations?
25
36
  true
26
37
  end
38
+
39
+ protected
40
+
41
+ attr_reader :method
27
42
  end
28
43
  end
29
44
  end
@@ -1,37 +1,76 @@
1
1
  class Sinclair
2
2
  module Matchers
3
+ # AddMethodTo checks whether a method was or not added by the call of a block
4
+ #
5
+ # This is used with a RSpec DSL method add_method(method_name).to(class_object)
6
+ #
7
+ # @author darthjee
8
+ #
9
+ # @example
10
+ # RSpec.configure do |config|
11
+ # config.include Sinclair::Matchers
12
+ # end
13
+ #
14
+ # class MyModel
15
+ # end
16
+ #
17
+ # RSpec.describe 'my test' do
18
+ # let(:klass) { Class.new(MyModel) }
19
+ # let(:builder) { Sinclair.new(klass) }
20
+ #
21
+ # before do
22
+ # builder.add_method(:class_name, 'self.class.name')
23
+ # end
24
+ #
25
+ # it do
26
+ # expect { builder.build }.to add_method(:class_name).to(klass)
27
+ # end
28
+ # end
3
29
  class AddMethodTo < RSpec::Matchers::BuiltIn::BaseMatcher
4
- attr_reader :method, :instance
5
-
6
- def initialize(instance, method)
7
- if instance.is_a?(Class)
8
- @instance_class = instance
30
+ # @overload initialize(klass, method)
31
+ # @param [Class] klass
32
+ # class where the method should be added to
33
+ #
34
+ # @overload initialize(instance, method)
35
+ # @param [Object] klass
36
+ # instance of the class where the method should be added to
37
+ #
38
+ # @param method
39
+ # method name
40
+ def initialize(target, method)
41
+ if target.is_a?(Class)
42
+ @klass = target
9
43
  else
10
- @instance = instance
44
+ @instance = target
11
45
  end
12
46
  @method = method
13
47
  end
14
48
 
49
+ # @return [String] expectation description
15
50
  def description
16
- "add method '#{method}' to #{instance_class} instances"
51
+ "add method '#{method}' to #{klass} instances"
17
52
  end
18
53
 
54
+ # @return [String] message on expectation failure
19
55
  def failure_message_for_should
20
- "expected '#{method}' to be added to #{instance_class} but " \
56
+ "expected '#{method}' to be added to #{klass} but " \
21
57
  "#{@initial_state ? 'it already existed' : "it didn't"}"
22
58
  end
23
59
 
60
+ # @return [String] message on expectation failure for negative expectation
24
61
  def failure_message_for_should_not
25
- "expected '#{method}' not to be added to #{instance_class} but it was"
62
+ "expected '#{method}' not to be added to #{klass} but it was"
26
63
  end
27
64
 
65
+ # @return [Boolean] expectation check
28
66
  def matches?(event_proc)
29
67
  return false unless event_proc.is_a?(Proc)
30
68
  raise_block_syntax_error if block_given?
31
69
  perform_change(event_proc)
32
- changed?
70
+ added?
33
71
  end
34
72
 
73
+ # definition needed for block matchers
35
74
  def supports_block_expectations?
36
75
  true
37
76
  end
@@ -44,7 +83,11 @@ class Sinclair
44
83
 
45
84
  protected
46
85
 
47
- def changed?
86
+ attr_reader :method, :instance
87
+
88
+ private
89
+
90
+ def added?
48
91
  !@initial_state && @final_state
49
92
  end
50
93
 
@@ -55,11 +98,11 @@ class Sinclair
55
98
  end
56
99
 
57
100
  def method_defined?
58
- instance_class.method_defined?(method)
101
+ klass.method_defined?(method)
59
102
  end
60
103
 
61
- def instance_class
62
- @instance_class ||= instance.class
104
+ def klass
105
+ @klass ||= instance.class
63
106
  end
64
107
 
65
108
  def raise_block_syntax_error
@@ -1,35 +1,52 @@
1
- class Sinclair::MethodDefinition
2
- attr_reader :name, :code, :block
3
-
4
- def initialize(name, code = nil, &block)
5
- @name = name
6
- @code = code
7
- @block = block
8
- end
1
+ class Sinclair
2
+ # Definition of the code or block to be aded as method
3
+ class MethodDefinition
4
+ # @overload initialize(name, code)
5
+ # @overload initialize(name, &block)
6
+ #
7
+ # @param name [String/Symbol] name of the method
8
+ # @param code [String] code to be evaluated as method
9
+ # @param block [Proc] block with code to be added as method
10
+ #
11
+ # @example
12
+ # Sinclair::Method.new(:name, '@name')
13
+ #
14
+ # @example
15
+ # Sinclair::Method.new(:name) { @name }
16
+ def initialize(name, code = nil, &block)
17
+ @name = name
18
+ @code = code
19
+ @block = block
20
+ end
9
21
 
10
- def build(clazz)
11
- if code.is_a?(String)
12
- build_code_method(clazz)
13
- else
14
- build_block_method(clazz)
22
+ # Adds the method to given klass
23
+ # @param klass [Class] class which will receive the new method
24
+ def build(klass)
25
+ if code.is_a?(String)
26
+ build_code_method(klass)
27
+ else
28
+ build_block_method(klass)
29
+ end
15
30
  end
16
- end
17
31
 
18
- private
32
+ private
19
33
 
20
- def build_block_method(clazz)
21
- clazz.send(:define_method, name, block)
22
- end
34
+ attr_reader :name, :code, :block
23
35
 
24
- def build_code_method(clazz)
25
- clazz.module_eval(code_definition, __FILE__, __LINE__ + 1)
26
- end
36
+ def build_block_method(klass)
37
+ klass.send(:define_method, name, block)
38
+ end
27
39
 
28
- def code_definition
29
- <<-CODE
40
+ def build_code_method(klass)
41
+ klass.module_eval(code_definition, __FILE__, __LINE__ + 1)
42
+ end
43
+
44
+ def code_definition
45
+ <<-CODE
30
46
  def #{name}
31
47
  #{code}
32
48
  end
33
- CODE
49
+ CODE
50
+ end
34
51
  end
35
52
  end
@@ -1,9 +1,35 @@
1
- module Sinclair::OptionsParser
2
- extend ActiveSupport::Concern
1
+ class Sinclair
2
+ # Concern for easily adding options
3
+ #
4
+ # @example
5
+ # class Sinclair
6
+ # class OptionsParser::Dummy
7
+ # include OptionsParser
8
+ #
9
+ # def initialize(options)
10
+ # @options = options.deep_dup
11
+ # end
12
+ # end
13
+ #
14
+ # def the_method
15
+ # return 'missing option' if options_object.switch.nil?
16
+ #
17
+ # if options_object.switch
18
+ # "The value is #{options_object.option_1}"
19
+ # else
20
+ # "The value is not #{options_object.option_1} but #{options_object.option_2}"
21
+ # end
22
+ # end
23
+ # end
24
+ module OptionsParser
25
+ extend ActiveSupport::Concern
3
26
 
4
- attr_reader :options
27
+ private
5
28
 
6
- def options_object
7
- @options_object ||= OpenStruct.new options
29
+ attr_reader :options
30
+
31
+ def options_object
32
+ @options_object ||= OpenStruct.new options
33
+ end
8
34
  end
9
35
  end
@@ -1,4 +1,4 @@
1
1
  class Sinclair
2
- VERSION = '1.1.0'
2
+ VERSION = '1.1.1'
3
3
  end
4
4
 
data/sinclair.gemspec CHANGED
@@ -25,5 +25,6 @@ Gem::Specification.new do |gem|
25
25
  gem.add_development_dependency 'simplecov', '~> 0.16.1'
26
26
  gem.add_development_dependency 'rubocop'
27
27
  gem.add_development_dependency 'pry-nav'
28
+ gem.add_development_dependency 'yard'
28
29
  end
29
30
 
@@ -1,8 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe MyClass do
4
- subject { clazz.new(attributes) }
5
- let(:clazz) { MyClass }
4
+ subject { klass.new(attributes) }
5
+ let(:klass) { MyClass }
6
6
  let(:name) { 'name' }
7
7
  let(:age) { 20 }
8
8
  let(:attributes) do
@@ -1,9 +1,9 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'Stand Alone' do
4
- let(:instance) { clazz.new }
5
- let(:clazz) { Class.new }
6
- let(:builder) { Sinclair.new(clazz) }
4
+ let(:instance) { klass.new }
5
+ let(:klass) { Class.new }
6
+ let(:builder) { Sinclair.new(klass) }
7
7
 
8
8
  before do
9
9
  builder.add_method(:twenty, '10 + 10')
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'yard' do
4
+ describe Sinclair::Matchers::AddMethodTo do
5
+ let(:klass) { Class.new(MyModel) }
6
+ let(:builder) { Sinclair.new(klass) }
7
+
8
+ before do
9
+ builder.add_method(:class_name, 'self.class.name')
10
+ end
11
+
12
+ it do
13
+ expect { builder.build }.to add_method(:class_name).to(klass)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'yard' do
4
+ describe Sinclair::OptionsParser do
5
+ let(:options) { { switch: false, option_1: 10, option_2: 20 } }
6
+ subject { described_class::Dummy.new(options) }
7
+
8
+ describe '#the_method' do
9
+ it 'returns the value for option given' do
10
+ expect(subject.the_method).to eq('The value is not 10 but 20')
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,149 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'yarn' do
4
+ describe Sinclair do
5
+ let(:klass) { Class.new(MyModel) }
6
+ let(:instance) { klass.new }
7
+ let(:builder) { Sinclair.new(klass) }
8
+ let(:default_value) { 10 }
9
+
10
+ describe '#initialize' do
11
+ describe '#total_price' do
12
+ before do
13
+ subject.eval_and_add_method(:total_price) do
14
+ code = 'self.value * self.quantity'
15
+ code.concat ' rescue 0' if options_object.rescue_error
16
+ code
17
+ end
18
+
19
+ subject.build
20
+ end
21
+
22
+ context 'without options' do
23
+ subject { Sinclair.new(klass, rescue_error: true) }
24
+
25
+ let(:klass) { Class.new(Purchase) }
26
+ let(:instance) { klass.new(2.3, 5) }
27
+
28
+ it 'evaluates into default_value' do
29
+ expect(instance.total_price).to eq(0)
30
+ end
31
+ end
32
+
33
+ context 'with options' do
34
+ subject { Sinclair.new(klass) }
35
+
36
+ let(:klass) { Class.new(Purchase) }
37
+ let(:instance) { klass.new(2.3, 5) }
38
+
39
+ it do
40
+ expect { instance.total_price }.to raise_error(NoMethodError)
41
+ end
42
+
43
+ context 'with attribute readers' do
44
+ before do
45
+ klass.send(:attr_reader, :value, :quantity)
46
+ end
47
+
48
+ it 'calculates total price' do
49
+ expect(instance.total_price).to eq(11.5)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ describe '#build' do
57
+ before do
58
+ value = default_value
59
+ builder.add_method(:default_value) { value }
60
+ builder.add_method(:value, '@value || default_value')
61
+ builder.add_method(:value=) { |val| @value = val }
62
+ end
63
+
64
+ context 'after the build' do
65
+ before { builder.build }
66
+ it 'creates the expected methods' do
67
+ expect(instance.value).to eq(10)
68
+ end
69
+
70
+ context 'when default value is overwritten' do
71
+ before do
72
+ instance.value = 20
73
+ end
74
+
75
+ it 'returns the new written value' do
76
+ expect(instance.value).to eq(20)
77
+ end
78
+ end
79
+ end
80
+
81
+ context 'calling the build' do
82
+ it do
83
+ expect do
84
+ builder.build
85
+ end.to change { instance.respond_to?(:default_value) }.to(true)
86
+ end
87
+ end
88
+ end
89
+
90
+ describe '#add_method' do
91
+ let(:klass) { Class.new(Person) }
92
+ let(:instance) { klass.new('john', 'wick') }
93
+
94
+ before do
95
+ builder.add_method(:full_name, '[first_name, last_name].join(" ")')
96
+ builder.add_method(:bond_name) { "#{last_name}, #{first_name} #{last_name}" }
97
+ builder.build
98
+ end
99
+
100
+ describe '#full_name' do
101
+ let(:klass) { Class.new(Person) }
102
+ let(:instance) { klass.new('john', 'wick') }
103
+
104
+ before do
105
+ builder.add_method(:full_name, '[first_name, last_name].join(" ")')
106
+ builder.build
107
+ end
108
+
109
+ it 'returns the full name' do
110
+ expect(instance.bond_name).to eq('wick, john wick')
111
+ end
112
+ end
113
+
114
+ describe '#bond_style' do
115
+ end
116
+ end
117
+
118
+ describe '#eval_and_add_method' do
119
+ subject { klass.new }
120
+
121
+ let(:klass) do
122
+ Class.new do
123
+ include InitialValuer
124
+ attr_writer :age
125
+ initial_value_for :age, 20
126
+ end
127
+ end
128
+
129
+ describe '#age' do
130
+ context 'when it has not been initialized' do
131
+ it do
132
+ expect(subject.age).to eq(20)
133
+ end
134
+ end
135
+
136
+ context 'when it has been initialized' do
137
+ before do
138
+ subject.age
139
+ subject.age = 30
140
+ end
141
+
142
+ it do
143
+ expect(subject.age).to eq(30)
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
@@ -1,8 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Sinclair::MethodDefinition do
4
- let(:clazz) { Class.new }
5
- let(:instance) { clazz.new }
4
+ let(:klass) { Class.new }
5
+ let(:instance) { klass.new }
6
6
 
7
7
  describe '#build' do
8
8
  let(:method_name) { :the_method }
@@ -13,10 +13,10 @@ describe Sinclair::MethodDefinition do
13
13
  subject { described_class.new(method_name, code) }
14
14
 
15
15
  before do
16
- subject.build(clazz)
16
+ subject.build(klass)
17
17
  end
18
18
 
19
- it 'adds the method to the clazz instance' do
19
+ it 'adds the method to the klass instance' do
20
20
  expect(instance).to respond_to(method_name)
21
21
  end
22
22
 
@@ -33,10 +33,10 @@ describe Sinclair::MethodDefinition do
33
33
  end
34
34
 
35
35
  before do
36
- subject.build(clazz)
36
+ subject.build(klass)
37
37
  end
38
38
 
39
- it 'adds the method to the clazz instance' do
39
+ it 'adds the method to the klass instance' do
40
40
  expect(instance).to respond_to(method_name)
41
41
  end
42
42
 
@@ -1,13 +1,13 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Sinclair::OptionsParser do
4
- let(:clazz) { described_class::Dummy }
4
+ let(:klass) { described_class::Dummy }
5
5
  let(:switched) { true }
6
6
  let(:value_1) { 'value1' }
7
7
  let(:options) { { switch: switched, option_1: value_1, option_2: 2} }
8
8
 
9
9
  subject do
10
- clazz.new(options)
10
+ klass.new(options)
11
11
  end
12
12
 
13
13
  it 'enables the given options to be acced' do
@@ -0,0 +1,13 @@
1
+ module InitialValuer
2
+ extend ActiveSupport::Concern
3
+
4
+ class_methods do
5
+ def initial_value_for(attribute, value)
6
+ builder = Sinclair.new(self, initial_value: value)
7
+ builder.eval_and_add_method(attribute) do
8
+ "@#{attribute} ||= #{options_object.initial_value}"
9
+ end
10
+ builder.build
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,2 @@
1
+ class MyModel
2
+ end
@@ -0,0 +1,8 @@
1
+ class Person
2
+ attr_reader :first_name, :last_name
3
+
4
+ def initialize(first_name, last_name)
5
+ @first_name = first_name
6
+ @last_name = last_name
7
+ end
8
+ end
@@ -0,0 +1,6 @@
1
+ class Purchase
2
+ def initialize(value, quantity)
3
+ @value = value
4
+ @quantity = quantity
5
+ end
6
+ end
@@ -1,7 +1,7 @@
1
1
  class ValidationBuilder < Sinclair
2
2
  delegate :expected, to: :options_object
3
3
 
4
- def initialize(clazz, options={})
4
+ def initialize(klass, options={})
5
5
  super
6
6
  end
7
7
 
@@ -10,6 +10,6 @@ class ValidationBuilder < Sinclair
10
10
  end
11
11
 
12
12
  def add_accessors(fields)
13
- clazz.send(:attr_accessor, *fields)
13
+ klass.send(:attr_accessor, *fields)
14
14
  end
15
15
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sinclair
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - DarthJee
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-07-03 00:00:00.000000000 Z
11
+ date: 2018-07-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: yard
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
111
125
  description: Gem for easy concern creation
112
126
  email:
113
127
  - darthjee@gmail.com
@@ -138,6 +152,9 @@ files:
138
152
  - spec/integration/readme/matcher_spec.rb
139
153
  - spec/integration/readme/my_class_spec.rb
140
154
  - spec/integration/readme_spec.rb
155
+ - spec/integration/yard/matchers/add_method_to_spec.rb
156
+ - spec/integration/yard/options_parser_spec.rb
157
+ - spec/integration/yard/sinclair_spec.rb
141
158
  - spec/lib/sinclair/matchers/add_method_spec.rb
142
159
  - spec/lib/sinclair/matchers/add_method_to_spec.rb
143
160
  - spec/lib/sinclair/matchers_spec.rb
@@ -148,9 +165,13 @@ files:
148
165
  - spec/support/fixture_helpers.rb
149
166
  - spec/support/models/dummy_builder.rb
150
167
  - spec/support/models/dummy_options_parser.rb
168
+ - spec/support/models/initial_valuer.rb
151
169
  - spec/support/models/my_builder.rb
152
170
  - spec/support/models/my_class.rb
153
171
  - spec/support/models/my_concern.rb
172
+ - spec/support/models/my_model.rb
173
+ - spec/support/models/person.rb
174
+ - spec/support/models/purchase.rb
154
175
  - spec/support/models/validator_builder.rb
155
176
  homepage: https://github.com/darthjee/sinclair
156
177
  licenses: []