eapi 0.0.1 → 0.1.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.
@@ -0,0 +1,40 @@
1
+ module Eapi
2
+ module ValueConverter
3
+ def self.convert_value(value)
4
+ if value.nil?
5
+ nil
6
+ elsif is_list? value
7
+ value_from_list value
8
+ elsif is_hash?(value)
9
+ value_from_hash value
10
+ else
11
+ value
12
+ end
13
+ end
14
+
15
+ private
16
+ def self.is_hash?(value)
17
+ value.respond_to? :to_h
18
+ end
19
+
20
+ def self.is_list?(value)
21
+ return false if value.kind_of?(Hash) || value.kind_of?(OpenStruct)
22
+
23
+ value.respond_to? :to_a
24
+ end
25
+
26
+ def self.value_from_list(value)
27
+ value.to_a.map { |e| convert_value e }.compact
28
+ end
29
+
30
+ def self.value_from_hash(value)
31
+ {}.tap do |hash|
32
+ value.to_h.each_pair do |k, v|
33
+ val = convert_value v
34
+ hash[k] = val unless val.nil?
35
+ end
36
+ hash.deep_symbolize_keys!
37
+ end
38
+ end
39
+ end
40
+ end
data/lib/eapi/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Eapi
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Eapi do
4
+
5
+ context 'basic behaviour' do
6
+ class MyTestKlass
7
+ include Eapi::Common
8
+
9
+ property :something
10
+ end
11
+
12
+ describe '#something (fluent setter/getter)' do
13
+ describe '#something as getter' do
14
+ it 'return the value' do
15
+ eapi = MyTestKlass.new something: :hey
16
+ expect(eapi.something).to eq :hey
17
+ end
18
+ end
19
+
20
+ describe '#something("val")' do
21
+ it 'set the value and return self' do
22
+ eapi = MyTestKlass.new something: :hey
23
+ res = eapi.something :other
24
+ expect(eapi).to be res
25
+ expect(eapi.something).to eq :other
26
+ end
27
+ end
28
+
29
+ describe '#set_something("val")' do
30
+ it 'set the value and return self' do
31
+ eapi = MyTestKlass.new something: :hey
32
+ res = eapi.set_something :other
33
+ expect(eapi).to be res
34
+ expect(eapi.something).to eq :other
35
+ end
36
+ end
37
+ end
38
+
39
+ describe '#get' do
40
+ it 'will use the getter' do
41
+ eapi = MyTestKlass.new something: :hey
42
+ expect(eapi.get(:something)).to eq :hey
43
+ expect(eapi.get('something')).to eq :hey
44
+ end
45
+
46
+ end
47
+
48
+ describe '#set' do
49
+ it 'will use the fluent setter' do
50
+ eapi = MyTestKlass.new
51
+ expect(eapi.set(:something, :hey)).to equal eapi
52
+ expect(eapi.get(:something)).to eq :hey
53
+ end
54
+ end
55
+
56
+ end
57
+
58
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Eapi do
4
+
5
+ context '#definition_for' do
6
+ class MyTestKlassDefinition
7
+ include Eapi::Common
8
+
9
+ property :something, type: Hash, unrecognised_option: 1
10
+ end
11
+
12
+ it 'will return the definition of a property, even with the unrecognised options (a copy of the hash, not editable)' do
13
+ definition = MyTestKlassDefinition.definition_for :something
14
+ expected = {type: Hash, unrecognised_option: 1}
15
+ expect(definition).to eq expected
16
+
17
+ #changing the definition
18
+ definition[:type] = Array
19
+
20
+ definition_2 = MyTestKlassDefinition.definition_for :something
21
+ expect(definition_2).to eq expected
22
+ expect(definition_2[:type]).to eq Hash
23
+ end
24
+ end
25
+
26
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Eapi do
4
+
5
+ context 'function initializer' do
6
+ class MyTestKlassOutside
7
+ include Eapi::Common
8
+
9
+ property :something
10
+ end
11
+
12
+ module Somewhere
13
+ class TestKlassInModule
14
+ include Eapi::Common
15
+
16
+ property :something
17
+ end
18
+ end
19
+
20
+ describe 'Eapi::Children' do
21
+ describe '#list' do
22
+ it 'returns the list of Eapi enabled classes' do
23
+ list = Eapi::Children.list
24
+ expect(list).to include(MyTestKlassOutside)
25
+ end
26
+ end
27
+
28
+ describe '#has?' do
29
+ it 'true if the given class is an Eapi enabled class' do
30
+ expect(Eapi::Children).not_to be_has('nope')
31
+ expect(Eapi::Children).to be_has(MyTestKlassOutside)
32
+ expect(Eapi::Children).to be_has('MyTestKlassOutside')
33
+ expect(Eapi::Children).to be_has('my_test_klass_outside')
34
+ end
35
+ end
36
+
37
+ describe '#get' do
38
+ it 'get the given class if it is an Eapi enabled class' do
39
+ expect(Eapi::Children.get('nope')).to be_nil
40
+ expect(Eapi::Children.get(MyTestKlassOutside)).to eq MyTestKlassOutside
41
+ expect(Eapi::Children.get('MyTestKlassOutside')).to eq MyTestKlassOutside
42
+ expect(Eapi::Children.get('my_test_klass_outside')).to eq MyTestKlassOutside
43
+ end
44
+ end
45
+ end
46
+
47
+ describe 'initialise using method calls to Eapi', :focus do
48
+ [
49
+ [:MyTestKlassOutside, MyTestKlassOutside],
50
+ [:my_test_klass_outside, MyTestKlassOutside],
51
+ [:Somewhere__TestKlassInModule, Somewhere::TestKlassInModule],
52
+ [:somewhere__test_klass_in_module, Somewhere::TestKlassInModule],
53
+ [:Somewhere_TestKlassInModule, Somewhere::TestKlassInModule],
54
+ [:somewhere_test_klass_in_module, Somewhere::TestKlassInModule],
55
+ ].each do |(meth, klass)|
56
+ describe "Eapi.#{meth}(...)" do
57
+ it "calls #{klass}.new" do
58
+ eapi = Eapi.send meth, something: :hey
59
+ expect(eapi).to be_a klass
60
+ expect(eapi.something).to eq :hey
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ it 'will raise NoMethodError if a valid class is not found' do
67
+ expect { Eapi.this_one_does_not_exist }.to raise_exception NoMethodError
68
+ end
69
+ end
70
+
71
+ end
data/spec/list_spec.rb ADDED
@@ -0,0 +1,124 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Eapi do
4
+
5
+ context 'list' do
6
+ class MyTestClassValMult
7
+ include Eapi::Common
8
+
9
+ property :something, multiple: true
10
+ end
11
+
12
+ it '#add_something' do
13
+ eapi = MyTestClassValMult.new something: [1, 2]
14
+ res = eapi.add_something 3
15
+ expect(res).to be eapi
16
+ expect(eapi.something).to eq [1, 2, 3]
17
+ end
18
+
19
+ it '#init_something called on first add if element is nil' do
20
+ eapi = MyTestClassValMult.new
21
+ res = eapi.add_something :a
22
+ expect(res).to be eapi
23
+ expect(eapi.something.to_a).to eq [:a]
24
+ end
25
+
26
+ class MyTestClassValMultImpl
27
+ include Eapi::Common
28
+
29
+ property :something, type: Set
30
+ end
31
+
32
+ class MyMultiple
33
+ def self.is_multiple?
34
+ true
35
+ end
36
+
37
+ def <<(x)
38
+ @elements ||= []
39
+ @elements << x
40
+ end
41
+
42
+ def to_a
43
+ @elements.to_a
44
+ end
45
+ end
46
+
47
+ class MyTestClassValMultImpl2
48
+ include Eapi::Common
49
+
50
+ property :something, type: MyMultiple
51
+ end
52
+
53
+ class MyMultipleEapi
54
+ include Eapi::Multiple
55
+
56
+ def <<(x)
57
+ @elements ||= []
58
+ @elements << x
59
+ end
60
+
61
+ def to_a
62
+ @elements.to_a
63
+ end
64
+ end
65
+
66
+ class MyTestClassValMultImpl3
67
+ include Eapi::Common
68
+
69
+ property :something, type: MyMultipleEapi
70
+ end
71
+
72
+ it 'if type is Array or Set, or responds true to is_multiple?, it is multiple implicitly + uses that class to initialize the property when adding' do
73
+ [
74
+ [MyTestClassValMult, Array],
75
+ [MyTestClassValMultImpl, Set],
76
+ [MyTestClassValMultImpl2, MyMultiple],
77
+ [MyTestClassValMultImpl3, MyMultipleEapi],
78
+ ].each do |(eapi_class, type_class)|
79
+ eapi = eapi_class.new
80
+ res = eapi.add_something :a
81
+ expect(res).to be eapi
82
+ expect(eapi.something.to_a).to eq [:a]
83
+ expect(eapi.something).to be_a_kind_of type_class
84
+ end
85
+ end
86
+
87
+ describe 'element validation' do
88
+ class MyTestClassValElements
89
+ include Eapi::Common
90
+ property :something, multiple: true, element_type: Hash
91
+ property :other, multiple: true, validate_element_with: ->(record, attr, value) do
92
+ record.errors.add(attr, "element must pass my custom validation") unless value == :valid_val
93
+ end
94
+ end
95
+
96
+ describe 'using `type_element` property in definition' do
97
+ it 'will validate the type of all the elements in the list' do
98
+ eapi = MyTestClassValElements.new
99
+ eapi.add_something 1
100
+ expect(eapi).not_to be_valid
101
+ expect(eapi.errors.full_messages).to eq ["Something element must be a Hash"]
102
+ expect(eapi.errors.messages).to eq({something: ["element must be a Hash"]})
103
+
104
+ eapi.something [{a: :b}]
105
+ expect(eapi).to be_valid
106
+ end
107
+ end
108
+
109
+ describe 'using `validate_element_with` property in definition' do
110
+ it 'will run that custom validation for all the elements in the list' do
111
+ eapi = MyTestClassValElements.new
112
+ eapi.add_other 1
113
+ expect(eapi).not_to be_valid
114
+ expect(eapi.errors.full_messages).to eq ["Other element must pass my custom validation"]
115
+ expect(eapi.errors.messages).to eq({other: ["element must pass my custom validation"]})
116
+
117
+ eapi.other [:valid_val]
118
+ expect(eapi).to be_valid
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  require 'bundler/setup'
2
2
  Bundler.setup
3
3
 
4
- require 'coveralls'
5
- Coveralls.wear!
4
+ require 'codeclimate-test-reporter'
5
+ CodeClimate::TestReporter.start
6
6
 
7
7
  require 'pry'
8
8
  require 'eapi'
data/spec/to_h_spec.rb ADDED
@@ -0,0 +1,87 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Eapi do
4
+
5
+ context '#to_h' do
6
+ class MyTestClassToH
7
+ include Eapi::Common
8
+
9
+ property :something, required: true
10
+ property :other
11
+ end
12
+
13
+ class MyTestObject
14
+ def to_h
15
+ {
16
+ a: 'hello'
17
+ }
18
+ end
19
+ end
20
+
21
+ class MyTestObjectComplex
22
+ def to_h
23
+ {
24
+ a: Set.new(['hello', 'world', MyTestObject.new])
25
+ }
26
+ end
27
+
28
+ def expected
29
+ {
30
+ a: [
31
+ 'hello',
32
+ 'world',
33
+ {a: 'hello'}
34
+ ]
35
+ }
36
+ end
37
+ end
38
+
39
+ it 'raise error if invalid' do
40
+ eapi = MyTestClassToH.new
41
+ expect { eapi.to_h }.to raise_error do |error|
42
+ expect(error).to be_a_kind_of Eapi::Errors::InvalidElementError
43
+ expect(error.message).to be_start_with "errors: [\"Something can't be blank\"], self: #<MyTestClassToH"
44
+ end
45
+
46
+ end
47
+
48
+ it 'create a hash with elements (calling to_h to each element), avoiding nils' do
49
+ eapi = MyTestClassToH.new
50
+ eapi.something 'hi'
51
+ expected = {something: 'hi'}
52
+ expect(eapi.to_h).to eq expected
53
+
54
+ eapi = MyTestClassToH.new
55
+ eapi.something(MyTestObject.new).other(true)
56
+ expected = {something: {a: 'hello'}, other: true}
57
+
58
+ expect(eapi.to_h).to eq expected
59
+ end
60
+
61
+ it 'hash with elements, all converted to basic Arrays and Hashes (keys as symbols), and exluding nils (if all validations pass)' do
62
+ list = Set.new [
63
+ OpenStruct.new(a: 1, 'b' => 2),
64
+ {c: 3, 'd' => 4},
65
+ nil
66
+ ]
67
+
68
+ other = MyTestObjectComplex.new
69
+
70
+ expected = {
71
+ something: [
72
+ {a: 1, b: 2},
73
+ {c: 3, d: 4},
74
+ ],
75
+
76
+ other: other.expected
77
+ }
78
+
79
+ eapi = MyTestClassToH.new
80
+ eapi.something list
81
+ eapi.other other
82
+
83
+ expect(eapi.to_h).to eq expected
84
+
85
+ end
86
+ end
87
+ end
data/spec/type_spec.rb ADDED
@@ -0,0 +1,86 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Eapi do
4
+
5
+ context 'type check' do
6
+ class OtherType
7
+ end
8
+
9
+ class MyTestTypeKlass
10
+ include Eapi::Common
11
+
12
+ is :one_thing, :other_thing, OtherType
13
+ end
14
+
15
+ describe '#is? and .is?' do
16
+ it 'true if asked for the same type' do
17
+ expect(MyTestTypeKlass).to be_is MyTestTypeKlass
18
+ expect(MyTestTypeKlass).to be_is 'MyTestTypeKlass'
19
+ expect(MyTestTypeKlass).to be_is :MyTestTypeKlass
20
+ expect(MyTestTypeKlass).to be_is :my_test_type_klass
21
+ end
22
+
23
+ it 'false if asked for other class' do
24
+ expect(MyTestTypeKlass).not_to be_is Hash
25
+ expect(MyTestTypeKlass).not_to be_is 'Hash'
26
+ expect(MyTestTypeKlass).not_to be_is :Hash
27
+ end
28
+
29
+ it 'true if asked for a type specified on the class with `is` method' do
30
+ expect(MyTestTypeKlass).not_to be_is :not_you
31
+ expect(MyTestTypeKlass).to be_is :one_thing
32
+ expect(MyTestTypeKlass).to be_is :other_thing
33
+ expect(MyTestTypeKlass).to be_is OtherType
34
+ expect(MyTestTypeKlass).to be_is :OtherType
35
+ end
36
+ end
37
+
38
+ describe '#is?' do
39
+ it 'behaves exactly like class method `.is?`' do
40
+ obj = MyTestTypeKlass.new
41
+
42
+ expect(obj).to be_is MyTestTypeKlass
43
+ expect(obj).to be_is 'MyTestTypeKlass'
44
+ expect(obj).to be_is :MyTestTypeKlass
45
+ expect(obj).to be_is :my_test_type_klass
46
+
47
+ expect(obj).not_to be_is Hash
48
+ expect(obj).not_to be_is 'Hash'
49
+ expect(obj).not_to be_is :Hash
50
+
51
+ expect(obj).not_to be_is :not_you
52
+ expect(obj).to be_is :one_thing
53
+ expect(obj).to be_is :other_thing
54
+ expect(obj).to be_is OtherType
55
+ expect(obj).to be_is :OtherType
56
+ end
57
+ end
58
+
59
+ describe '`#is_a_specific_type?` and `#is_an_other_type?`' do
60
+ it 'will use #is? inside' do
61
+ obj = MyTestTypeKlass.new
62
+ expect(obj).to be_is_a_my_test_type_klass
63
+ expect(obj).not_to be_is_a_not_you
64
+ expect(obj).to be_is_an_one_thing
65
+ expect(obj).to be_is_an_other_thing
66
+ end
67
+
68
+ it 'method_missing still works' do
69
+ expect { MyTestTypeKlass.new.some_other_method? }.to raise_exception(NoMethodError)
70
+ end
71
+ end
72
+
73
+ describe '`.is_a_specific_type?` and `.is_an_other_type?`' do
74
+ it 'will use .is? inside' do
75
+ expect(MyTestTypeKlass).to be_is_a_my_test_type_klass
76
+ expect(MyTestTypeKlass).not_to be_is_a_not_you
77
+ expect(MyTestTypeKlass).to be_is_an_one_thing
78
+ expect(MyTestTypeKlass).to be_is_an_other_thing
79
+ end
80
+
81
+ it 'method_missing still works' do
82
+ expect { MyTestTypeKlass.some_other_method? }.to raise_exception(NoMethodError)
83
+ end
84
+ end
85
+ end
86
+ end