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.
- checksums.yaml +4 -4
- data/.travis.yml +5 -0
- data/Gemfile +1 -0
- data/README.md +495 -2
- data/eapi.gemspec +0 -1
- data/lib/eapi.rb +10 -2
- data/lib/eapi/children.rb +30 -0
- data/lib/eapi/common.rb +8 -15
- data/lib/eapi/definition_runner.rb +109 -0
- data/lib/eapi/methods/names.rb +0 -4
- data/lib/eapi/methods/properties.rb +1 -109
- data/lib/eapi/methods/types.rb +52 -5
- data/lib/eapi/type_checker.rb +16 -0
- data/lib/eapi/value_converter.rb +40 -0
- data/lib/eapi/version.rb +1 -1
- data/spec/basic_spec.rb +58 -0
- data/spec/definition_spec.rb +26 -0
- data/spec/function_spec.rb +71 -0
- data/spec/list_spec.rb +124 -0
- data/spec/spec_helper.rb +2 -2
- data/spec/to_h_spec.rb +87 -0
- data/spec/type_spec.rb +86 -0
- data/spec/{eapi_validations_spec.rb → validations_spec.rb} +59 -21
- metadata +20 -25
- data/.coveralls.yml +0 -1
- data/spec/eapi_basic_spec.rb +0 -39
- data/spec/eapi_list_spec.rb +0 -92
- data/spec/eapi_to_h_spec.rb +0 -42
data/eapi.gemspec
CHANGED
@@ -27,7 +27,6 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_development_dependency "pry-rescue"
|
28
28
|
spec.add_development_dependency "pry-stack_explorer"
|
29
29
|
spec.add_development_dependency "pry-doc"
|
30
|
-
spec.add_development_dependency "coveralls"
|
31
30
|
|
32
31
|
spec.add_dependency 'activesupport', '~> 4'
|
33
32
|
spec.add_dependency 'activemodel', '~> 4'
|
data/lib/eapi.rb
CHANGED
@@ -3,14 +3,22 @@ require 'active_model'
|
|
3
3
|
|
4
4
|
require 'eapi/version'
|
5
5
|
require 'eapi/errors'
|
6
|
+
require 'eapi/children'
|
6
7
|
require 'eapi/multiple'
|
8
|
+
require 'eapi/definition_runner'
|
9
|
+
require 'eapi/type_checker'
|
7
10
|
require 'eapi/methods'
|
11
|
+
require 'eapi/value_converter'
|
8
12
|
require 'eapi/common'
|
9
13
|
|
10
14
|
|
11
15
|
module Eapi
|
12
16
|
def self.method_missing(method, *args, &block)
|
13
|
-
klass =
|
14
|
-
klass
|
17
|
+
klass = Eapi::Children.get(method)
|
18
|
+
if klass
|
19
|
+
klass.new *args, &block
|
20
|
+
else
|
21
|
+
super
|
22
|
+
end
|
15
23
|
end
|
16
24
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Eapi
|
2
|
+
module Children
|
3
|
+
CHILDREN = {}
|
4
|
+
|
5
|
+
def self.list
|
6
|
+
CHILDREN.values
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.append(klass)
|
10
|
+
k = self.key_for klass
|
11
|
+
CHILDREN[k] = klass
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.get(klass_name)
|
15
|
+
k = self.key_for klass_name
|
16
|
+
CHILDREN[k] ||
|
17
|
+
CHILDREN[k.gsub('__', '/')] ||
|
18
|
+
CHILDREN.select { |key, _| key.gsub('/', '_') == k }.values.first
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.has?(klass_name)
|
22
|
+
!!self.get(klass_name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.key_for(klass_name)
|
26
|
+
k = klass_name.to_s
|
27
|
+
k.underscore
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/eapi/common.rb
CHANGED
@@ -1,28 +1,21 @@
|
|
1
1
|
module Eapi
|
2
2
|
module Common
|
3
3
|
extend ActiveSupport::Concern
|
4
|
-
included do
|
5
|
-
|
6
|
-
include
|
4
|
+
included do |klass|
|
5
|
+
Eapi::Children.append klass
|
6
|
+
klass.send :include, ActiveModel::Validations
|
7
|
+
klass.send :include, Eapi::Methods::Properties::InstanceMethods
|
8
|
+
klass.send :include, Eapi::Methods::Types::InstanceMethods
|
7
9
|
end
|
8
10
|
|
9
11
|
def initialize(** properties)
|
10
12
|
properties.each do |k, v|
|
11
|
-
normal_setter =
|
13
|
+
normal_setter = Eapi::Methods::Names.setter k
|
12
14
|
#TODO: what to do with unrecognised properties
|
13
15
|
send normal_setter, v if respond_to? normal_setter
|
14
16
|
end
|
15
17
|
end
|
16
18
|
|
17
|
-
def method_missing(method, *args)
|
18
|
-
catch(:response) do
|
19
|
-
Eapi::Methods::Types.check_asking_type method, self
|
20
|
-
|
21
|
-
# if nothing catch -> continue super
|
22
|
-
super
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
19
|
def to_h
|
27
20
|
raise Eapi::Errors::InvalidElementError, "errors: #{errors.full_messages}, self: #{self.inspect}" unless valid?
|
28
21
|
|
@@ -32,8 +25,7 @@ module Eapi
|
|
32
25
|
def create_hash
|
33
26
|
{}.tap do |hash|
|
34
27
|
self.class.properties.each do |prop|
|
35
|
-
|
36
|
-
val = (stored.present? && stored.respond_to?(:to_h)) ? stored.to_h : stored
|
28
|
+
val = Eapi::ValueConverter.convert_value(get(prop))
|
37
29
|
hash[prop] = val unless val.nil?
|
38
30
|
end
|
39
31
|
end
|
@@ -44,5 +36,6 @@ module Eapi
|
|
44
36
|
include Eapi::Methods::Types::ClassMethods
|
45
37
|
include Eapi::Methods::Properties::ClassMethods
|
46
38
|
end
|
39
|
+
|
47
40
|
end
|
48
41
|
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Eapi
|
2
|
+
class DefinitionRunner < Struct.new(:klass, :field, :definition)
|
3
|
+
def run
|
4
|
+
run_multiple_accessor
|
5
|
+
run_init
|
6
|
+
run_validations
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
def run_validations
|
11
|
+
run_required
|
12
|
+
run_validate_type
|
13
|
+
run_validate_with
|
14
|
+
run_validate_element_type
|
15
|
+
run_validate_element_with
|
16
|
+
end
|
17
|
+
|
18
|
+
def run_validate_type
|
19
|
+
if type
|
20
|
+
klass.send :validates_each, field do |record, attr, value|
|
21
|
+
unless Eapi::TypeChecker.new(type).is_valid_type?(value)
|
22
|
+
record.errors.add(attr, "must be a #{type}")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def run_validate_element_with
|
29
|
+
if multiple && validate_element_with
|
30
|
+
klass.send :validates_each, field do |record, attr, value|
|
31
|
+
if value.respond_to?(:each)
|
32
|
+
value.each do |v|
|
33
|
+
validate_element_with.call(record, attr, v)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def run_validate_element_type
|
41
|
+
if multiple && element_type
|
42
|
+
klass.send :validates_each, field do |record, attr, value|
|
43
|
+
if value.respond_to?(:each)
|
44
|
+
value.each do |v|
|
45
|
+
record.errors.add(attr, "element must be a #{element_type}") unless v.kind_of?(element_type)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def run_validate_with
|
53
|
+
if validate_with
|
54
|
+
klass.send :validates_each, field do |record, attr, value|
|
55
|
+
validate_with.call(record, attr, value)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def run_required
|
61
|
+
if required
|
62
|
+
klass.send :validates_presence_of, field
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def run_init
|
67
|
+
if type || multiple
|
68
|
+
klass.send :define_init, field, type || Array
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def run_multiple_accessor
|
73
|
+
if multiple
|
74
|
+
klass.send :define_multiple_accessor, field
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def type_multiple?(type)
|
79
|
+
return false if type.nil?
|
80
|
+
return true if type == Array || type == Set
|
81
|
+
|
82
|
+
type.respond_to?(:is_multiple?) && type.is_multiple?
|
83
|
+
end
|
84
|
+
|
85
|
+
def validate_element_with
|
86
|
+
definition.fetch(:validate_element_with, nil)
|
87
|
+
end
|
88
|
+
|
89
|
+
def multiple
|
90
|
+
definition.fetch(:multiple, false) || type_multiple?(type)
|
91
|
+
end
|
92
|
+
|
93
|
+
def required
|
94
|
+
definition.fetch(:required, false)
|
95
|
+
end
|
96
|
+
|
97
|
+
def validate_with
|
98
|
+
definition.fetch(:validate_with, nil)
|
99
|
+
end
|
100
|
+
|
101
|
+
def element_type
|
102
|
+
definition.fetch(:element_type, nil)
|
103
|
+
end
|
104
|
+
|
105
|
+
def type
|
106
|
+
definition.fetch(:type, nil)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
data/lib/eapi/methods/names.rb
CHANGED
@@ -37,7 +37,7 @@ module Eapi
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def run_definition(field, definition)
|
40
|
-
DefinitionRunner.new(self, field, definition).run
|
40
|
+
Eapi::DefinitionRunner.new(self, field, definition).run
|
41
41
|
end
|
42
42
|
|
43
43
|
private :run_definition
|
@@ -45,113 +45,5 @@ module Eapi
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
class DefinitionRunner < Struct.new(:klass, :field, :definition)
|
49
|
-
def run
|
50
|
-
run_multiple_accessor
|
51
|
-
run_init
|
52
|
-
run_validations
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
def run_validations
|
57
|
-
run_required
|
58
|
-
run_validate_type
|
59
|
-
run_validate_with
|
60
|
-
run_validate_type_element
|
61
|
-
run_validate_element_with
|
62
|
-
end
|
63
|
-
|
64
|
-
def run_validate_type
|
65
|
-
if type
|
66
|
-
klass.send :validates_each, field do |record, attr, value|
|
67
|
-
return if value.nil? && !required
|
68
|
-
|
69
|
-
record.errors.add(attr, "must be a #{type}") unless value.kind_of?(type)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def run_validate_element_with
|
75
|
-
if multiple && validate_element_with
|
76
|
-
validates_each field do |record, attr, value|
|
77
|
-
if value.respond_to?(:each)
|
78
|
-
value.each do |v|
|
79
|
-
validate_element_with.call(record, attr, v)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
def run_validate_type_element
|
87
|
-
if multiple && type_element
|
88
|
-
validates_each field do |record, attr, value|
|
89
|
-
if value.respond_to?(:each)
|
90
|
-
value.each do |v|
|
91
|
-
record.errors.add(attr, "element must be a #{type}") unless v.kind_of?(type)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def run_validate_with
|
99
|
-
if validate_with
|
100
|
-
klass.send :validates_each, field do |record, attr, value|
|
101
|
-
validate_with.call(record, attr, value)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
def run_required
|
107
|
-
if required
|
108
|
-
klass.send :validates_presence_of, field
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
def run_init
|
113
|
-
if type || multiple
|
114
|
-
klass.send :define_init, field, type || Array
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def run_multiple_accessor
|
119
|
-
if multiple
|
120
|
-
klass.send :define_multiple_accessor, field
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
def type_multiple?(type)
|
125
|
-
return false if type.nil?
|
126
|
-
return true if type == Array || type == Set
|
127
|
-
|
128
|
-
type.respond_to?(:is_multiple?) && type.is_multiple?
|
129
|
-
end
|
130
|
-
|
131
|
-
def validate_element_with
|
132
|
-
definition.fetch(:validate_element_with, nil)
|
133
|
-
end
|
134
|
-
|
135
|
-
def multiple
|
136
|
-
definition.fetch(:multiple, false) || type_multiple?(type)
|
137
|
-
end
|
138
|
-
|
139
|
-
def required
|
140
|
-
definition.fetch(:required, false)
|
141
|
-
end
|
142
|
-
|
143
|
-
def validate_with
|
144
|
-
definition.fetch(:validate_with, nil)
|
145
|
-
end
|
146
|
-
|
147
|
-
def type_element
|
148
|
-
definition.fetch(:type_element, nil)
|
149
|
-
end
|
150
|
-
|
151
|
-
def type
|
152
|
-
definition.fetch(:type, nil)
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
48
|
end
|
157
49
|
end
|
data/lib/eapi/methods/types.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
module Eapi
|
2
2
|
module Methods
|
3
|
-
|
4
3
|
module Types
|
5
4
|
def self.type_question_method(method)
|
6
5
|
ms = method.to_s
|
7
|
-
|
6
|
+
return false unless ms.end_with?('?')
|
7
|
+
if ms.start_with?('is_a_')
|
8
8
|
ms.sub('is_a_', '').sub('?', '')
|
9
|
+
elsif ms.start_with?('is_an_')
|
10
|
+
ms.sub('is_an_', '').sub('?', '')
|
9
11
|
else
|
10
12
|
nil
|
11
13
|
end
|
@@ -14,19 +16,64 @@ module Eapi
|
|
14
16
|
def self.check_asking_type(method, obj)
|
15
17
|
type = Types.type_question_method method
|
16
18
|
if type
|
17
|
-
|
19
|
+
obj.is?(type)
|
20
|
+
else
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.to_type_sym(x)
|
26
|
+
x.to_s.underscore.to_sym
|
27
|
+
end
|
28
|
+
|
29
|
+
module IsAnOtherTypeMethods
|
30
|
+
def respond_to_missing?(method, include_all)
|
31
|
+
if Types.type_question_method(method).present?
|
32
|
+
true
|
33
|
+
else
|
34
|
+
super
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def method_missing(method, *args, &block)
|
39
|
+
resp = Types.check_asking_type method, self
|
40
|
+
if resp.nil?
|
41
|
+
super
|
42
|
+
else
|
43
|
+
resp
|
44
|
+
end
|
18
45
|
end
|
19
46
|
end
|
20
47
|
|
48
|
+
module InstanceMethods
|
49
|
+
def is?(type)
|
50
|
+
self.class.is?(type)
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.included(klass)
|
54
|
+
klass.send :include, IsAnOtherTypeMethods
|
55
|
+
end
|
56
|
+
end
|
21
57
|
|
22
58
|
module ClassMethods
|
59
|
+
def self.included(klass)
|
60
|
+
klass.send :include, IsAnOtherTypeMethods
|
61
|
+
end
|
62
|
+
|
23
63
|
def is?(type)
|
24
|
-
|
64
|
+
type_sym = Types.to_type_sym type
|
65
|
+
|
66
|
+
return true if self == type || Types.to_type_sym(self) == type_sym
|
67
|
+
return false unless @i_am_a.present?
|
68
|
+
|
69
|
+
!!@i_am_a.include?(type_sym) # force it to be a bool
|
25
70
|
end
|
26
71
|
|
27
72
|
def is(*types)
|
73
|
+
ts = types.map { |t| Types.to_type_sym t }
|
74
|
+
|
28
75
|
@i_am_a ||= []
|
29
|
-
@i_am_a.concat
|
76
|
+
@i_am_a.concat ts
|
30
77
|
end
|
31
78
|
end
|
32
79
|
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Eapi
|
2
|
+
class TypeChecker < Struct.new(:type)
|
3
|
+
def is_valid_type?(value)
|
4
|
+
value.nil? || is_same_type?(value) || poses_as_type?(value)
|
5
|
+
end
|
6
|
+
|
7
|
+
private
|
8
|
+
def is_same_type?(value)
|
9
|
+
value.kind_of?(type)
|
10
|
+
end
|
11
|
+
|
12
|
+
def poses_as_type?(value)
|
13
|
+
value.respond_to?(:is?) && value.is?(type)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|