eapi 0.1.2 → 0.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/.travis.yml +1 -2
- data/README.md +85 -26
- data/eapi.gemspec +1 -0
- data/lib/eapi.rb +7 -2
- data/lib/eapi/common.rb +11 -28
- data/lib/eapi/definition_runners.rb +3 -0
- data/lib/eapi/definition_runners/list.rb +60 -0
- data/lib/eapi/definition_runners/property.rb +100 -0
- data/lib/eapi/definition_runners/runner.rb +44 -0
- data/lib/eapi/item.rb +31 -0
- data/lib/eapi/list.rb +145 -0
- data/lib/eapi/methods/accessor.rb +1 -23
- data/lib/eapi/methods/properties.rb +47 -12
- data/lib/eapi/{multiple.rb → multiple_value.rb} +1 -1
- data/lib/eapi/version.rb +1 -1
- data/spec/basic_spec.rb +36 -35
- data/spec/definition_spec.rb +1 -1
- data/spec/extension_spec.rb +2 -2
- data/spec/function_spec.rb +70 -41
- data/spec/list_elements_spec.rb +123 -0
- data/spec/list_spec.rb +378 -81
- data/spec/to_h_spec.rb +1 -1
- data/spec/type_spec.rb +2 -2
- data/spec/validations_spec.rb +8 -8
- metadata +25 -4
- data/lib/eapi/definition_runner.rb +0 -109
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 24226b6df180842850c926be63af60c33803e6e0
|
4
|
+
data.tar.gz: 1764202eb7a457a16bde2590b25909af05d4d17b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: abef4e5a06756f1f32db42e60e0358451d524620ea0d7dc21af6f4929da5eea21f86a74a9930142164b219ba68ecb362cefe6f7115baffda67ba93a2477d7ec2
|
7
|
+
data.tar.gz: d67597321bb8c496167825f17b558c2e0e6e02b2bd75064eee1a7126146d2ffa0ecdb42742f5f912c19cce4ee45c5ef43e6d81158a5081dfbda353bab9960a09
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -25,14 +25,15 @@ Or install it yourself as:
|
|
25
25
|
|
26
26
|
### Ruby version
|
27
27
|
|
28
|
-
Works with ruby 2.
|
28
|
+
Works with ruby 2.1, tested with MRI 2.1.1
|
29
29
|
|
30
30
|
### Gem dependencies
|
31
31
|
|
32
|
-
This gem uses ActiveSupport (version 4) and also the ActiveModel Validations (version 4)
|
32
|
+
This gem uses ActiveSupport (version 4) and also the ActiveModel Validations (version 4). It also uses fluent_accessors gem.
|
33
33
|
|
34
34
|
Extracted from the gemspec:
|
35
35
|
```
|
36
|
+
spec.add_dependency 'fluent_accessors', '~> 1'
|
36
37
|
spec.add_dependency 'activesupport', '~> 4'
|
37
38
|
spec.add_dependency 'activemodel', '~> 4'
|
38
39
|
```
|
@@ -41,11 +42,11 @@ spec.add_dependency 'activemodel', '~> 4'
|
|
41
42
|
|
42
43
|
### including EAPI into your class
|
43
44
|
|
44
|
-
Just include the module `Eapi::
|
45
|
+
Just include the module `Eapi::Item` into your class.
|
45
46
|
|
46
47
|
```ruby
|
47
48
|
class MyTestKlass
|
48
|
-
include Eapi::
|
49
|
+
include Eapi::Item
|
49
50
|
|
50
51
|
property :something
|
51
52
|
end
|
@@ -59,7 +60,7 @@ For now any unrecognised property in the hash will be ignored. This may change i
|
|
59
60
|
|
60
61
|
```ruby
|
61
62
|
class MyTestKlass
|
62
|
-
include Eapi::
|
63
|
+
include Eapi::Item
|
63
64
|
|
64
65
|
property :something
|
65
66
|
end
|
@@ -78,14 +79,14 @@ To show this feature and all the combinations for method names, we'll use the 2
|
|
78
79
|
|
79
80
|
```ruby
|
80
81
|
class MyTestKlassOutside
|
81
|
-
include Eapi::
|
82
|
+
include Eapi::Item
|
82
83
|
|
83
84
|
property :something
|
84
85
|
end
|
85
86
|
|
86
87
|
module Somewhere
|
87
88
|
class TestKlassInModule
|
88
|
-
include Eapi::
|
89
|
+
include Eapi::Item
|
89
90
|
|
90
91
|
property :something
|
91
92
|
end
|
@@ -116,7 +117,7 @@ We define properties in our class with the instruction `property` as shown:
|
|
116
117
|
|
117
118
|
```ruby
|
118
119
|
class MyTestKlass
|
119
|
-
include Eapi::
|
120
|
+
include Eapi::Item
|
120
121
|
|
121
122
|
property :one
|
122
123
|
property :two
|
@@ -169,13 +170,15 @@ x.one # => :fluent
|
|
169
170
|
res.equal? x # => true
|
170
171
|
```
|
171
172
|
|
172
|
-
### Convert to hashes: `to_h` and `create_hash`
|
173
|
+
### Convert to hashes: `render`, `to_h` and `create_hash`
|
173
174
|
|
174
|
-
All Eapi classes respond to `
|
175
|
+
All Eapi classes respond to `render` and return a hash (for `Item` classes) or an array (for `List` classes), as it is the main purpose of this gem. It will execute any validation (see property definition), and if everything is ok, it will convert it to a simple hash structure.
|
176
|
+
|
177
|
+
`Item` classes will invoke `render` when receiving `to_h`, while `List` classes will do the same when receiving `to_a`
|
175
178
|
|
176
179
|
#### Methods involved
|
177
180
|
|
178
|
-
Inside, `
|
181
|
+
Inside, `render` will call `valid?`, raise an error of type `Eapi::Errors::InvalidElementError` if something is not right, and if everything is ok it will call `create_hash`.
|
179
182
|
|
180
183
|
The `create_hash` method will create a hash with the properties as keys. Each value will be "converted".
|
181
184
|
|
@@ -203,13 +206,13 @@ class ComplexValue
|
|
203
206
|
end
|
204
207
|
|
205
208
|
class ExampleEapi
|
206
|
-
include Eapi::
|
209
|
+
include Eapi::Item
|
207
210
|
|
208
211
|
property :something, required: true
|
209
212
|
property :other
|
210
213
|
end
|
211
214
|
|
212
|
-
# TESTING `
|
215
|
+
# TESTING `render`
|
213
216
|
|
214
217
|
list = Set.new [
|
215
218
|
OpenStruct.new(a: 1, 'b' => 2),
|
@@ -218,7 +221,9 @@ list = Set.new [
|
|
218
221
|
]
|
219
222
|
|
220
223
|
eapi = ExampleEapi.new something: list, other: ComplexValue.new
|
221
|
-
|
224
|
+
|
225
|
+
# same as eapi.to_h
|
226
|
+
eapi.render # =>
|
222
227
|
# {
|
223
228
|
# something: [
|
224
229
|
# {a: 1, b: 2},
|
@@ -249,7 +254,7 @@ example:
|
|
249
254
|
|
250
255
|
```ruby
|
251
256
|
class TestKlass
|
252
|
-
include Eapi::
|
257
|
+
include Eapi::Item
|
253
258
|
|
254
259
|
property :something, required: true
|
255
260
|
end
|
@@ -268,7 +273,7 @@ example:
|
|
268
273
|
|
269
274
|
```ruby
|
270
275
|
class TestKlass
|
271
|
-
include Eapi::
|
276
|
+
include Eapi::Item
|
272
277
|
|
273
278
|
property :something, type: Hash
|
274
279
|
end
|
@@ -283,7 +288,7 @@ Also, if a type is specified, then a `init_property_name` method is created that
|
|
283
288
|
|
284
289
|
```ruby
|
285
290
|
class TestKlass
|
286
|
-
include Eapi::
|
291
|
+
include Eapi::Item
|
287
292
|
|
288
293
|
property :something, type: Hash
|
289
294
|
end
|
@@ -298,7 +303,7 @@ A symbol or a string can also be specified as class name in `type` option, and i
|
|
298
303
|
|
299
304
|
```ruby
|
300
305
|
class TestKlass
|
301
|
-
include Eapi::
|
306
|
+
include Eapi::Item
|
302
307
|
|
303
308
|
property :something, type: "Hash"
|
304
309
|
end
|
@@ -319,7 +324,7 @@ example:
|
|
319
324
|
|
320
325
|
```ruby
|
321
326
|
class TestKlass
|
322
|
-
include Eapi::
|
327
|
+
include Eapi::Item
|
323
328
|
|
324
329
|
property :something, validate_with: ->(record, attr, value) do
|
325
330
|
record.errors.add(attr, "must pass my custom validation") unless value == :valid_val
|
@@ -338,7 +343,7 @@ All other ActiveModel::Validations can be used:
|
|
338
343
|
|
339
344
|
```ruby
|
340
345
|
class TestKlass
|
341
|
-
include Eapi::
|
346
|
+
include Eapi::Item
|
342
347
|
|
343
348
|
property :something
|
344
349
|
validates :something, numericality: true
|
@@ -360,7 +365,7 @@ You can see (but not edit) the definition of a property calling the `definition_
|
|
360
365
|
|
361
366
|
```ruby
|
362
367
|
class TestKlass
|
363
|
-
include Eapi::
|
368
|
+
include Eapi::Item
|
364
369
|
|
365
370
|
property :something, type: Hash, unrecognised_option: 1
|
366
371
|
end
|
@@ -384,7 +389,7 @@ A property marked as `multiple` will be initialised with an empty array. If no t
|
|
384
389
|
|
385
390
|
```ruby
|
386
391
|
class TestKlass
|
387
|
-
include Eapi::
|
392
|
+
include Eapi::Item
|
388
393
|
|
389
394
|
property :something, multiple: true
|
390
395
|
end
|
@@ -398,7 +403,7 @@ If the property is `nil` when `add_property_name` is called, then it will call `
|
|
398
403
|
|
399
404
|
```ruby
|
400
405
|
class TestKlass
|
401
|
-
include Eapi::
|
406
|
+
include Eapi::Item
|
402
407
|
|
403
408
|
property :something, multiple: true
|
404
409
|
end
|
@@ -431,7 +436,7 @@ class MyCustomList
|
|
431
436
|
end
|
432
437
|
|
433
438
|
class TestKlass
|
434
|
-
include Eapi::
|
439
|
+
include Eapi::Item
|
435
440
|
|
436
441
|
property :p1, multiple: true
|
437
442
|
property :p2, type: Array
|
@@ -453,7 +458,7 @@ We can also specify `validate_element_with` option, and it will act the same as
|
|
453
458
|
|
454
459
|
```ruby
|
455
460
|
class TestKlass
|
456
|
-
include Eapi::
|
461
|
+
include Eapi::Item
|
457
462
|
|
458
463
|
property :something, multiple: true, element_type: Hash
|
459
464
|
property :other, multiple: true, validate_element_with: ->(record, attr, value) do
|
@@ -480,6 +485,60 @@ eapi.other [:valid_val]
|
|
480
485
|
eapi.valid? # => true
|
481
486
|
```
|
482
487
|
|
488
|
+
### `List` classes
|
489
|
+
|
490
|
+
An Eapi `List` is to an Array as an Eapi `Item` is to a Hash.
|
491
|
+
|
492
|
+
It will render itself into an array of elements. It can store a list of elements that will be validated and rendered.
|
493
|
+
|
494
|
+
It works using an internal list of elements, to whom it delegates most of the behaviour. Its interface is compatible with an Array, including ActiveSupport methods.
|
495
|
+
|
496
|
+
#### accessor to internal element list: `_list`
|
497
|
+
|
498
|
+
The internal list of elements of an Eapi `List` object can be accessed using the `_list` method, that is always an `Array`.
|
499
|
+
|
500
|
+
#### fluent adder: `add`
|
501
|
+
|
502
|
+
Similar to the `set_x` methods for properties, this method will add an element to the internal list and return `self`.
|
503
|
+
|
504
|
+
#### elements definition: `elements`
|
505
|
+
|
506
|
+
Similar to the `property` macro to define a property and its requirements, `List` classes can set the definition to be used for its elements using the macro `elements`.
|
507
|
+
|
508
|
+
The options for that definition is:
|
509
|
+
|
510
|
+
* `required`: it will provoke the list validation to fail if there is at least 1 element in the list
|
511
|
+
* `unique`: it will provoke the list validation to fail if there are duplicated elements in the list
|
512
|
+
* `element_type` or `type`: it will provoke the list validation to fail if an element does not complies with the given type validation (see type validation on `Item`)
|
513
|
+
* `validate_element_with` or `validate_with`: it will execute the given callable object to validate each element, similar to the `validate_element_with` option in the property definition.
|
514
|
+
|
515
|
+
#### example
|
516
|
+
|
517
|
+
```ruby
|
518
|
+
class MyListKlass
|
519
|
+
include Eapi::List
|
520
|
+
|
521
|
+
elements unique: true
|
522
|
+
end
|
523
|
+
|
524
|
+
l = MyListKlass.new
|
525
|
+
|
526
|
+
# fluent adder
|
527
|
+
l.add(1).add(2).add(3)
|
528
|
+
|
529
|
+
# internal list accessor
|
530
|
+
l._list # => [1, 2, 3]
|
531
|
+
|
532
|
+
# render method (same as #to_a)
|
533
|
+
l.render # => [1, 2, 3]
|
534
|
+
|
535
|
+
l.valid? # => true
|
536
|
+
|
537
|
+
l.add(1)
|
538
|
+
|
539
|
+
l.valid? # => false
|
540
|
+
```
|
541
|
+
|
483
542
|
### Pose as other types
|
484
543
|
|
485
544
|
An Eapi class can poses as other types, for purposes of `type` checking in a property definition. We use the class method `is` for this.
|
@@ -492,7 +551,7 @@ example:
|
|
492
551
|
|
493
552
|
```ruby
|
494
553
|
class SuperTestKlass
|
495
|
-
include Eapi::
|
554
|
+
include Eapi::Item
|
496
555
|
end
|
497
556
|
|
498
557
|
class TestKlass < SuperTestKlass
|
data/eapi.gemspec
CHANGED
@@ -28,6 +28,7 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.add_development_dependency "pry-stack_explorer"
|
29
29
|
spec.add_development_dependency "pry-doc"
|
30
30
|
|
31
|
+
spec.add_dependency 'fluent_accessors', '~> 1'
|
31
32
|
spec.add_dependency 'activesupport', '~> 4'
|
32
33
|
spec.add_dependency 'activemodel', '~> 4'
|
33
34
|
end
|
data/lib/eapi.rb
CHANGED
@@ -1,15 +1,18 @@
|
|
1
|
+
require 'fluent_accessors'
|
1
2
|
require 'active_support/all'
|
2
3
|
require 'active_model'
|
3
4
|
|
4
5
|
require 'eapi/version'
|
5
6
|
require 'eapi/errors'
|
6
7
|
require 'eapi/children'
|
7
|
-
require 'eapi/
|
8
|
-
require 'eapi/
|
8
|
+
require 'eapi/multiple_value'
|
9
|
+
require 'eapi/definition_runners'
|
9
10
|
require 'eapi/type_checker'
|
10
11
|
require 'eapi/methods'
|
11
12
|
require 'eapi/value_converter'
|
12
13
|
require 'eapi/common'
|
14
|
+
require 'eapi/item'
|
15
|
+
require 'eapi/list'
|
13
16
|
|
14
17
|
|
15
18
|
module Eapi
|
@@ -29,6 +32,8 @@ module Eapi
|
|
29
32
|
def self.extended(mod)
|
30
33
|
mod.class_eval <<-CODE
|
31
34
|
Common = Eapi::Common
|
35
|
+
Item = Eapi::Item
|
36
|
+
List = Eapi::List
|
32
37
|
Children = Eapi::Children
|
33
38
|
CODE
|
34
39
|
Eapi.add_method_missing mod
|
data/lib/eapi/common.rb
CHANGED
@@ -3,46 +3,29 @@ module Eapi
|
|
3
3
|
def self.add_features(klass)
|
4
4
|
Eapi::Children.append klass
|
5
5
|
klass.send :include, ActiveModel::Validations
|
6
|
+
klass.send :include, Eapi::Common::Basic
|
6
7
|
klass.send :include, Eapi::Methods::Properties::InstanceMethods
|
7
8
|
klass.send :include, Eapi::Methods::Types::InstanceMethods
|
8
9
|
|
9
10
|
klass.send :extend, ClassMethods
|
10
11
|
end
|
11
12
|
|
12
|
-
|
13
|
-
def
|
14
|
-
|
13
|
+
module Basic
|
14
|
+
def initialize(** properties)
|
15
|
+
properties.each do |k, v|
|
16
|
+
normal_setter = Eapi::Methods::Names.setter k
|
17
|
+
#TODO: what to do with unrecognised properties
|
18
|
+
send normal_setter, v if respond_to? normal_setter
|
19
|
+
end
|
15
20
|
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.included(klass)
|
19
|
-
Eapi::Common.add_features klass
|
20
|
-
end
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
normal_setter = Eapi::Methods::Names.setter k
|
25
|
-
#TODO: what to do with unrecognised properties
|
26
|
-
send normal_setter, v if respond_to? normal_setter
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def to_h
|
31
|
-
raise Eapi::Errors::InvalidElementError, "errors: #{errors.full_messages}, self: #{self.inspect}" unless valid?
|
32
|
-
|
33
|
-
create_hash
|
34
|
-
end
|
35
|
-
|
36
|
-
def create_hash
|
37
|
-
{}.tap do |hash|
|
38
|
-
self.class.properties.each do |prop|
|
39
|
-
val = Eapi::ValueConverter.convert_value(get(prop))
|
40
|
-
hash[prop] = val unless val.nil?
|
41
|
-
end
|
22
|
+
def validate!
|
23
|
+
raise Eapi::Errors::InvalidElementError, "errors: #{errors.full_messages}, self: #{self.inspect}" unless valid?
|
42
24
|
end
|
43
25
|
end
|
44
26
|
|
45
27
|
module ClassMethods
|
28
|
+
include FluentAccessors
|
46
29
|
include Eapi::Methods::Accessor
|
47
30
|
include Eapi::Methods::Types::ClassMethods
|
48
31
|
include Eapi::Methods::Properties::ClassMethods
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Eapi
|
2
|
+
module DefinitionRunners
|
3
|
+
|
4
|
+
|
5
|
+
class List < Struct.new(:klass, :definition)
|
6
|
+
def run
|
7
|
+
run_validations
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
def run_validations
|
12
|
+
run_required
|
13
|
+
run_validate_element_type
|
14
|
+
run_validate_element_with
|
15
|
+
run_validate_uniqueness
|
16
|
+
end
|
17
|
+
|
18
|
+
def run_validate_uniqueness
|
19
|
+
if unique?
|
20
|
+
Runner.unique klass: klass, field: :_list
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def run_validate_element_with
|
25
|
+
if validate_element_with
|
26
|
+
Runner.validate_element_with klass: klass, field: :_list, validate_element_with: validate_element_with
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def run_validate_element_type
|
31
|
+
if element_type
|
32
|
+
Runner.validate_element_type(klass: klass, field: :_list, element_type: element_type)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def run_required
|
37
|
+
if required?
|
38
|
+
Runner.required(klass: klass, field: :_list)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def required?
|
43
|
+
definition.fetch(:required, false)
|
44
|
+
end
|
45
|
+
|
46
|
+
def unique?
|
47
|
+
definition.fetch(:unique, false)
|
48
|
+
end
|
49
|
+
|
50
|
+
def validate_element_with
|
51
|
+
definition.fetch(:validate_element_with, nil) || definition.fetch(:validate_with, nil)
|
52
|
+
end
|
53
|
+
|
54
|
+
def element_type
|
55
|
+
definition.fetch(:element_type, nil) || definition.fetch(:type, nil)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|