sinclair 1.1.3 → 1.2.0
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 +4 -4
- data/.rubocop.yml +24 -0
- data/.rubocop_todo.yml +1 -1
- data/README.md +126 -103
- data/lib/sinclair.rb +40 -10
- data/lib/sinclair/method_definition.rb +96 -15
- data/lib/sinclair/version.rb +1 -1
- data/spec/integration/readme/my_class_spec.rb +13 -10
- data/spec/integration/readme/my_model_spec.rb +29 -0
- data/spec/integration/readme/sinclair/matchers_spec.rb +24 -0
- data/spec/integration/readme/sinclair_spec.rb +25 -0
- data/spec/integration/{matcher_spec.rb → sinclair/matchers_spec.rb} +7 -7
- data/spec/integration/yard/my_builder_spec.rb +27 -0
- data/spec/integration/yard/{matchers → sinclair/matchers}/add_method_spec.rb +2 -2
- data/spec/integration/yard/{matchers → sinclair/matchers}/add_method_to_spec.rb +2 -2
- data/spec/integration/yard/sinclair/method_definition_spec.rb +54 -0
- data/spec/integration/yard/{options_parser_spec.rb → sinclair/options_parser_spec.rb} +5 -4
- data/spec/integration/yard/sinclair_spec.rb +17 -19
- data/spec/lib/sinclair/matchers/add_method_spec.rb +7 -8
- data/spec/lib/sinclair/matchers/add_method_to_spec.rb +28 -26
- data/spec/lib/sinclair/method_definition_spec.rb +75 -20
- data/spec/lib/sinclair/options_parser_spec.rb +14 -15
- data/spec/lib/sinclair_spec.rb +43 -43
- data/spec/spec_helper.rb +0 -1
- data/spec/support/models/default_value.rb +20 -0
- data/spec/support/models/my_builder.rb +14 -13
- metadata +12 -8
- data/spec/integration/readme/matcher_spec.rb +0 -27
- data/spec/integration/readme_spec.rb +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b1f884160da67fa0a41d2b19c5fb1f2186b6a5dfb8518e70d7e624667e7d7a35
|
4
|
+
data.tar.gz: aff0a41c90770ec096c19963abfcea8a6435ee0c725ad90a70dedad800b03646
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 455434bf9a034eb258b6cc52d0ff3f0a1f0d3671f9ca96c9f892d18ef1435946fc982821fcb34b077409b3f05265cbe493d2820e51804c79ca23da5e58d7ee12
|
7
|
+
data.tar.gz: 8360e97280c678e0326b2be9227b16401059c7a8b37b97e3a0b1ffaa2177ffc4bec7df7a01d8dc8eb2accb216a8c68ade20783c3d4b77ce75a7acff9368ac8a0
|
data/.rubocop.yml
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require: rubocop-rspec
|
1
2
|
inherit_from: .rubocop_todo.yml
|
2
3
|
|
3
4
|
AllCops:
|
@@ -9,3 +10,26 @@ Metrics/BlockLength:
|
|
9
10
|
|
10
11
|
Metrics/LineLength:
|
11
12
|
Max: 100
|
13
|
+
|
14
|
+
Lint/AmbiguousBlockAssociation:
|
15
|
+
Exclude:
|
16
|
+
- 'spec/**/*_spec.rb'
|
17
|
+
|
18
|
+
RSpec/AlignLeftLetBrace:
|
19
|
+
Enabled: true
|
20
|
+
|
21
|
+
RSpec/InstanceVariable:
|
22
|
+
Exclude:
|
23
|
+
- 'spec/integration/yard/sinclair/method_definition_spec.rb'
|
24
|
+
- 'spec/lib/sinclair/method_definition_spec.rb'
|
25
|
+
|
26
|
+
RSpec/MultipleExpectations:
|
27
|
+
Exclude:
|
28
|
+
- spec/integration/yard/sinclair/method_definition_spec.rb
|
29
|
+
- spec/lib/sinclair_spec.rb
|
30
|
+
- spec/integration/readme/my_model_spec.rb
|
31
|
+
|
32
|
+
RSpec/NestedGroups:
|
33
|
+
Max: 4
|
34
|
+
Exclude:
|
35
|
+
- spec/integration/yard/**/*.rb
|
data/.rubocop_todo.yml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# This configuration was generated by
|
2
2
|
# `rubocop --auto-gen-config`
|
3
|
-
# on
|
3
|
+
# on 2019-03-29 10:57:21 +0000 using RuboCop version 0.58.1.
|
4
4
|
# The point is for the user to remove these configuration records
|
5
5
|
# one by one as the offenses are removed from the code base.
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
data/README.md
CHANGED
@@ -3,33 +3,34 @@ Sinclair
|
|
3
3
|
[](https://codeclimate.com/github/darthjee/sinclair)
|
4
4
|
[](https://codeclimate.com/github/darthjee/sinclair/coverage)
|
5
5
|
[](https://codeclimate.com/github/darthjee/sinclair)
|
6
|
+
[](https://badge.fury.io/rb/sinclair)
|
6
7
|
|
7
8
|
|
8
9
|

|
9
10
|
|
10
11
|
This gem helps the creation of complex concern with class methods
|
11
12
|
|
13
|
+
Yard Documentation
|
14
|
+
-------------------
|
15
|
+
https://www.rubydoc.info/gems/sinclair/1.2.0
|
16
|
+
|
12
17
|
Installation
|
13
18
|
---------------
|
14
19
|
- Install it
|
15
20
|
|
16
|
-
|
17
|
-
|
18
|
-
|
21
|
+
```ruby
|
22
|
+
gem install sinclair
|
23
|
+
```
|
19
24
|
|
20
25
|
- Or add Sinclairn to your `Gemfile` and `bundle install`:
|
21
26
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
```bash
|
27
|
-
bundle install sinclair
|
28
|
-
```
|
27
|
+
```ruby
|
28
|
+
gem 'sinclair'
|
29
|
+
```
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
```bash
|
32
|
+
bundle install sinclair
|
33
|
+
```
|
33
34
|
|
34
35
|
Usage
|
35
36
|
---------------
|
@@ -38,93 +39,87 @@ adding methods to your class or by extending it for more complex logics
|
|
38
39
|
|
39
40
|
- Stand Alone usage:
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
class Clazz
|
44
|
-
end
|
42
|
+
```ruby
|
45
43
|
|
46
|
-
|
47
|
-
|
48
|
-
builder.add_method(:twenty, '10 + 10')
|
49
|
-
builder.add_method(:eighty) { 4 * twenty }
|
50
|
-
builder.build
|
44
|
+
class Clazz
|
45
|
+
end
|
51
46
|
|
52
|
-
|
47
|
+
builder = Sinclair.new(Clazz)
|
53
48
|
|
54
|
-
|
55
|
-
|
56
|
-
|
49
|
+
builder.add_method(:twenty, '10 + 10')
|
50
|
+
builder.add_method(:eighty) { 4 * twenty }
|
51
|
+
builder.build
|
57
52
|
|
58
|
-
|
53
|
+
instance = Clazz.new
|
59
54
|
|
60
|
-
|
61
|
-
|
62
|
-
|
55
|
+
puts "Twenty => #{instance.twenty}" # Twenty => 20
|
56
|
+
puts "Eighty => #{instance.eighty}" # Eighty => 80
|
57
|
+
```
|
63
58
|
|
64
59
|
- Extending the builder
|
65
60
|
|
66
|
-
|
61
|
+
```ruby
|
67
62
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
def initialize(klass, options={})
|
72
|
-
super
|
73
|
-
end
|
63
|
+
class ValidationBuilder < Sinclair
|
64
|
+
delegate :expected, to: :options_object
|
74
65
|
|
75
|
-
|
76
|
-
|
77
|
-
|
66
|
+
def initialize(klass, options={})
|
67
|
+
super
|
68
|
+
end
|
78
69
|
|
79
|
-
|
80
|
-
|
81
|
-
end
|
70
|
+
def add_validation(field)
|
71
|
+
add_method("#{field}_valid?", "#{field}.is_a?#{expected}")
|
82
72
|
end
|
83
73
|
|
84
|
-
|
85
|
-
|
74
|
+
def add_accessors(fields)
|
75
|
+
klass.send(:attr_accessor, *fields)
|
76
|
+
end
|
77
|
+
end
|
86
78
|
|
87
|
-
|
88
|
-
|
89
|
-
builder = ::ValidationBuilder.new(self, expected: expected_class)
|
79
|
+
module MyConcern
|
80
|
+
extend ActiveSupport::Concern
|
90
81
|
|
91
|
-
|
92
|
-
|
82
|
+
class_methods do
|
83
|
+
def validate(*fields, expected_class)
|
84
|
+
builder = ::ValidationBuilder.new(self, expected: expected_class)
|
93
85
|
|
94
|
-
|
95
|
-
|
96
|
-
end
|
86
|
+
validatable_fields.concat(fields)
|
87
|
+
builder.add_accessors(fields)
|
97
88
|
|
98
|
-
|
89
|
+
fields.each do |field|
|
90
|
+
builder.add_validation(field)
|
99
91
|
end
|
100
92
|
|
101
|
-
|
102
|
-
@validatable_fields ||= []
|
103
|
-
end
|
93
|
+
builder.build
|
104
94
|
end
|
105
95
|
|
106
|
-
def
|
107
|
-
|
108
|
-
public_send("#{field}_valid?")
|
109
|
-
end
|
96
|
+
def validatable_fields
|
97
|
+
@validatable_fields ||= []
|
110
98
|
end
|
111
99
|
end
|
112
100
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
validate :age, :legs, Integer
|
117
|
-
|
118
|
-
def initialize(name: nil, surname: nil, age: nil, legs: nil)
|
119
|
-
@name = name
|
120
|
-
@surname = surname
|
121
|
-
@age = age
|
122
|
-
@legs = legs
|
101
|
+
def valid?
|
102
|
+
self.class.validatable_fields.all? do |field|
|
103
|
+
public_send("#{field}_valid?")
|
123
104
|
end
|
124
105
|
end
|
106
|
+
end
|
125
107
|
|
126
|
-
|
127
|
-
|
108
|
+
class MyClass
|
109
|
+
include MyConcern
|
110
|
+
validate :name, :surname, String
|
111
|
+
validate :age, :legs, Integer
|
112
|
+
|
113
|
+
def initialize(name: nil, surname: nil, age: nil, legs: nil)
|
114
|
+
@name = name
|
115
|
+
@surname = surname
|
116
|
+
@age = age
|
117
|
+
@legs = legs
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
instance = MyClass.new
|
122
|
+
```
|
128
123
|
|
129
124
|
the instance will respond to the methods
|
130
125
|
```name``` ```name=``` ```name_valid?```
|
@@ -133,34 +128,62 @@ adding methods to your class or by extending it for more complex logics
|
|
133
128
|
```legs``` ```legs=``` ```legs_valid?```
|
134
129
|
```valid?```.
|
135
130
|
|
136
|
-
|
131
|
+
```ruby
|
132
|
+
valid_object = MyClass.new(
|
133
|
+
name: :name,
|
134
|
+
surname: 'surname',
|
135
|
+
age: 20,
|
136
|
+
legs: 2
|
137
|
+
)
|
138
|
+
valid_object.valid? # returns true
|
139
|
+
```
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
|
143
|
+
invalid_object = MyClass.new(
|
144
|
+
name: 'name',
|
145
|
+
surname: 'surname',
|
146
|
+
age: 20,
|
147
|
+
legs: 2
|
148
|
+
)
|
149
|
+
invalid_object.valid? # returns false
|
150
|
+
```
|
151
|
+
|
152
|
+
- Caching the result
|
153
|
+
If wanted, the result of the method can be stored in an
|
154
|
+
instance variable with the same name
|
155
|
+
|
156
|
+
```ruby
|
157
|
+
class MyModel
|
158
|
+
attr_accessor :base, :expoent
|
159
|
+
end
|
160
|
+
|
161
|
+
builder = Sinclair.new(MyModel)
|
162
|
+
|
163
|
+
builder.add_method(:cached_power, cached: true) do
|
164
|
+
base ** expoent
|
165
|
+
end
|
166
|
+
|
167
|
+
# equivalent of builder.add_method(:cached_power) do
|
168
|
+
# @cached_power ||= base ** expoent
|
169
|
+
# end
|
137
170
|
|
138
|
-
|
139
|
-
name: :name,
|
140
|
-
surname: 'surname',
|
141
|
-
age: 20,
|
142
|
-
legs: 2
|
143
|
-
)
|
144
|
-
valid_object.valid? # returns true
|
145
|
-
```
|
171
|
+
builder.build
|
146
172
|
|
147
|
-
|
173
|
+
model.base = 3
|
174
|
+
model.expoent = 2
|
148
175
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
legs: 2
|
154
|
-
)
|
155
|
-
invalid_object.valid? # returns false
|
156
|
-
```
|
176
|
+
model.cached_power # returns 9
|
177
|
+
model.expoent = 3
|
178
|
+
model.cached_power # returns 9 (from cache)
|
179
|
+
```
|
157
180
|
|
158
181
|
RSspec matcher
|
159
182
|
---------------
|
160
183
|
|
161
184
|
You can use the provided matcher to check that your builder is adding a method correctly
|
162
185
|
|
163
|
-
|
186
|
+
```ruby
|
164
187
|
|
165
188
|
class DefaultValue
|
166
189
|
delegate :build, to: :builder
|
@@ -209,19 +232,19 @@ You can use the provided matcher to check that your builder is adding a method c
|
|
209
232
|
end
|
210
233
|
end
|
211
234
|
end
|
212
|
-
|
235
|
+
```
|
213
236
|
|
214
|
-
|
237
|
+
```bash
|
215
238
|
|
216
|
-
|
217
|
-
|
239
|
+
> bundle exec rspec
|
240
|
+
```
|
218
241
|
|
219
|
-
|
242
|
+
```string
|
220
243
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
244
|
+
DefaultValue
|
245
|
+
when the builder runs
|
246
|
+
should add method 'the_method' to #<Class:0x0000000146c160> instances
|
247
|
+
when the builder runs
|
248
|
+
should add method 'the_method' to #<Class:0x0000000143a1b0> instances
|
226
249
|
|
227
|
-
|
250
|
+
```
|
data/lib/sinclair.rb
CHANGED
@@ -8,7 +8,7 @@ require 'active_support/all'
|
|
8
8
|
#
|
9
9
|
# Builder that add instance methods to a class
|
10
10
|
#
|
11
|
-
# @example
|
11
|
+
# @example Stand alone usage
|
12
12
|
# class MyModel
|
13
13
|
# end
|
14
14
|
#
|
@@ -38,7 +38,7 @@ class Sinclair
|
|
38
38
|
# @param options [Hash] open hash options to be used by builders inheriting from Sinclair
|
39
39
|
# through the Sinclair::OptionsParser concern
|
40
40
|
#
|
41
|
-
# @example
|
41
|
+
# @example Preparing builder
|
42
42
|
#
|
43
43
|
# class Purchase
|
44
44
|
# def initialize(value, quantity)
|
@@ -49,9 +49,39 @@ class Sinclair
|
|
49
49
|
#
|
50
50
|
# builder = Sinclair.new(Purchase)
|
51
51
|
#
|
52
|
-
# @example
|
52
|
+
# @example Passing building options (Used on subclasses)
|
53
53
|
#
|
54
|
-
#
|
54
|
+
# class MyBuilder < Sinclair
|
55
|
+
# def add_methods
|
56
|
+
# if options_object.rescue_error
|
57
|
+
# add_safe_method
|
58
|
+
# else
|
59
|
+
# add_method(:symbolize) { @variable.to_sym }
|
60
|
+
# end
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# def add_safe_method
|
64
|
+
# add_method(:symbolize) do
|
65
|
+
# begin
|
66
|
+
# @variable.to_sym
|
67
|
+
# rescue StandardError
|
68
|
+
# :default
|
69
|
+
# end
|
70
|
+
# end
|
71
|
+
# end
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# class MyModel
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# builder = MyBuilder.new(MyModel, rescue_error: true)
|
78
|
+
#
|
79
|
+
# builder.add_method
|
80
|
+
# builder.build
|
81
|
+
#
|
82
|
+
# instance = MyModel.new
|
83
|
+
#
|
84
|
+
# instance.symbolize # returns :default
|
55
85
|
def initialize(klass, options = {})
|
56
86
|
@klass = klass
|
57
87
|
@options = options
|
@@ -59,7 +89,7 @@ class Sinclair
|
|
59
89
|
|
60
90
|
# builds all the methods added into the klass
|
61
91
|
#
|
62
|
-
# @example
|
92
|
+
# @example Adding a default value method
|
63
93
|
#
|
64
94
|
# class MyModel
|
65
95
|
# end
|
@@ -114,13 +144,13 @@ class Sinclair
|
|
114
144
|
#
|
115
145
|
# Person.new('john', 'wick').bond_name # returns 'wick, john wick'
|
116
146
|
# @return [Array<MethodDefinition>]
|
117
|
-
def add_method(name, code = nil, &block)
|
118
|
-
definitions << MethodDefinition.new(name, code, &block)
|
147
|
+
def add_method(name, code = nil, **options, &block)
|
148
|
+
definitions << MethodDefinition.new(name, code, **options, &block)
|
119
149
|
end
|
120
150
|
|
121
151
|
# Evaluetes a block which will result in a String, the method code
|
122
152
|
#
|
123
|
-
# @example
|
153
|
+
# @example Building a initial value class method
|
124
154
|
#
|
125
155
|
# module InitialValuer
|
126
156
|
# extend ActiveSupport::Concern
|
@@ -147,7 +177,7 @@ class Sinclair
|
|
147
177
|
# object.age = 30
|
148
178
|
# object.age # 30
|
149
179
|
#
|
150
|
-
# @example
|
180
|
+
# @example Adding option for rescue
|
151
181
|
#
|
152
182
|
# class Purchase
|
153
183
|
# def initialize(value, quantity)
|
@@ -168,7 +198,7 @@ class Sinclair
|
|
168
198
|
#
|
169
199
|
# Purchase.new(2.3, 5).total_price # raises error
|
170
200
|
#
|
171
|
-
# @example
|
201
|
+
# @example Using option for rescue
|
172
202
|
#
|
173
203
|
# builder = Sinclair.new(Purchase, rescue_error: true)
|
174
204
|
#
|