eapi 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|