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.
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 = const_get("Eapi::#{method}")
14
- klass.new *args, &block
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
- include ActiveModel::Validations
6
- include Eapi::Methods::Properties::InstanceMethods
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 = "#{k}="
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
- stored = get(prop)
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
@@ -6,10 +6,6 @@ module Eapi
6
6
  "init_#{field}"
7
7
  end
8
8
 
9
- def self.clear(field)
10
- "clear_#{field}"
11
- end
12
-
13
9
  def self.add(field)
14
10
  "add_#{field}"
15
11
  end
@@ -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
@@ -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
- if ms.start_with?('is_a_') && ms.end_with?('?')
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
- throw :response, obj.class.is?(type)
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
- @i_am_a && @i_am_a.include?(type.to_sym)
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(types.map(&:to_sym))
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