contextuable 0.2.0 → 0.3.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/README.md +9 -0
- data/lib/contextuable/class_methods.rb +37 -0
- data/lib/contextuable/instance_methods.rb +92 -0
- data/lib/contextuable.rb +34 -102
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f078d3e26b5f6a206f595db13edf2eeed2149f00
|
4
|
+
data.tar.gz: 2bffb3821243b8b7617d4b782a8cb6dadfc3f519
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 95857c57a2be144c38be622a911b71f5e22e3d92c643a2d37961fbc9fe3e2640457ae602441d4c1790942139739a5902b1ca9f7e4a484115aa15a7ba607959fb
|
7
|
+
data.tar.gz: 1f4a390b7c957a89044b03ecb5509060c863111f774dd86c5ce63c7e6bae6ee2efe9b92d8c9f4146c31efd7db1a1b44e1a470c73a4dbf8de8d78e6dd92e0bc96
|
data/README.md
CHANGED
@@ -71,6 +71,15 @@ i.not_permitted
|
|
71
71
|
|
72
72
|
### Building better Structs
|
73
73
|
|
74
|
+
**no_method_error**
|
75
|
+
```ruby
|
76
|
+
class Example < Contextuable
|
77
|
+
no_method_error
|
78
|
+
end
|
79
|
+
|
80
|
+
Example.new(foo: :bar).hello # => Error: NoMethodError
|
81
|
+
```
|
82
|
+
|
74
83
|
**required**
|
75
84
|
```ruby
|
76
85
|
class Example < Contextuable
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class Contextuable
|
2
|
+
module ClassMethods
|
3
|
+
|
4
|
+
def settings
|
5
|
+
@settings ||= {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def required(*names)
|
9
|
+
settings[:required] = names.map(&:to_sym)
|
10
|
+
end
|
11
|
+
|
12
|
+
def no_method_error(input = true)
|
13
|
+
settings[:no_method_error] = input
|
14
|
+
end
|
15
|
+
|
16
|
+
def open_struct_behavior(input = true)
|
17
|
+
settings[:no_method_error] = !input
|
18
|
+
end
|
19
|
+
|
20
|
+
def ensure_presence(*names)
|
21
|
+
settings[:presence_required] = names.map(&:to_sym)
|
22
|
+
end
|
23
|
+
|
24
|
+
def aliases(*names)
|
25
|
+
settings[:equivalents] ||= []
|
26
|
+
settings[:equivalents] << names.map(&:to_sym)
|
27
|
+
end
|
28
|
+
|
29
|
+
def defaults(hash)
|
30
|
+
settings[:defaults] = hash
|
31
|
+
end
|
32
|
+
|
33
|
+
def permit(*names)
|
34
|
+
settings[:permitted] = names.map(&:to_sym)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
class Contextuable
|
2
|
+
module InstanceMethods
|
3
|
+
def initialize(hash = {})
|
4
|
+
check_input_errors(hash)
|
5
|
+
hash = hash.select{|k, v| _permitted.include?(k.to_sym) } if _only_permitted?
|
6
|
+
@attrs = _defaults.merge(hash)
|
7
|
+
attrs.each do |k, v|
|
8
|
+
define_contextuable_method(k, v)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def method_missing(name, *args, &block)
|
13
|
+
if ary = find_in_equivalents(name)
|
14
|
+
_from_equivalents(ary)
|
15
|
+
elsif name =~ /\A\w+=\z/
|
16
|
+
set_attribute_macro(name, *args, &block)
|
17
|
+
else
|
18
|
+
out = provided_macro(name)
|
19
|
+
return out[:out] if out
|
20
|
+
raise NoMethodError if _no_method_error
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def find_in_equivalents(name)
|
25
|
+
found = nil
|
26
|
+
_equivalents.each do |ary|
|
27
|
+
found = ary if ary.include?(name.to_sym)
|
28
|
+
break if found
|
29
|
+
end
|
30
|
+
found
|
31
|
+
end
|
32
|
+
|
33
|
+
def _from_equivalents(ary)
|
34
|
+
out = nil
|
35
|
+
ary.each do |method|
|
36
|
+
out = attrs[method.to_sym]
|
37
|
+
break if out
|
38
|
+
end
|
39
|
+
out
|
40
|
+
end
|
41
|
+
|
42
|
+
def _only_permitted?
|
43
|
+
_permitted.any?
|
44
|
+
end
|
45
|
+
|
46
|
+
def _permitted
|
47
|
+
_get_config[:permitted] || []
|
48
|
+
end
|
49
|
+
|
50
|
+
def _equivalents
|
51
|
+
_get_config[:equivalents] || []
|
52
|
+
end
|
53
|
+
|
54
|
+
def _presence_required
|
55
|
+
_get_config[:presence_required] || []
|
56
|
+
end
|
57
|
+
|
58
|
+
def _no_method_error
|
59
|
+
!_get_config[:no_method_error] == false
|
60
|
+
end
|
61
|
+
|
62
|
+
def _defaults
|
63
|
+
_get_config[:defaults] || {}
|
64
|
+
end
|
65
|
+
|
66
|
+
def _required_args
|
67
|
+
_get_config[:required] || []
|
68
|
+
end
|
69
|
+
|
70
|
+
def _get_config
|
71
|
+
self.class.settings
|
72
|
+
end
|
73
|
+
|
74
|
+
def check_input_errors(hash)
|
75
|
+
unless hash.class <= Hash
|
76
|
+
fail WrongArgument, "[Contextuable ERROR]: `#{self.class}` expects to receive a `Hash` or and object having `Hash` as ancestor."
|
77
|
+
end
|
78
|
+
|
79
|
+
_required_args.map(&:to_sym).each do |r|
|
80
|
+
unless hash.keys.map(&:to_sym).include?(r)
|
81
|
+
fail RequiredFieldNotPresent, "[Contextuable ERROR]: `#{self.class}` expect to be initialized with `#{r}` as an attribute."
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
_presence_required.map(&:to_sym).each do |r|
|
86
|
+
if hash[r].nil?
|
87
|
+
fail PresenceRequired, "[Contextuable ERROR]: `#{self.class}` expects to receive an attribute named `#{r}` not beeing `nil`"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/lib/contextuable.rb
CHANGED
@@ -1,48 +1,33 @@
|
|
1
1
|
class Contextuable
|
2
|
-
VERSION = "0.
|
2
|
+
VERSION = "0.3.0"
|
3
|
+
autoload :ClassMethods, 'contextuable/class_methods'
|
4
|
+
autoload :InstanceMethods, 'contextuable/instance_methods'
|
3
5
|
|
4
6
|
class RequiredFieldNotPresent < ArgumentError; end
|
5
7
|
class PresenceRequired < ArgumentError; end
|
6
8
|
class WrongArgument < ArgumentError; end
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
12
|
-
|
13
|
-
def ensure_presence(*names)
|
14
|
-
@_presence_required = names.map(&:to_sym)
|
15
|
-
end
|
16
|
-
|
17
|
-
def aliases(*names)
|
18
|
-
@_equivalents ||= []
|
19
|
-
@_equivalents << names.map(&:to_sym)
|
20
|
-
end
|
21
|
-
|
22
|
-
def defaults(hash)
|
23
|
-
@_defaults = hash
|
24
|
-
end
|
25
|
-
|
26
|
-
def permit(*names)
|
27
|
-
@_permitted = names.map(&:to_sym)
|
28
|
-
end
|
10
|
+
def self.inherited(subclass)
|
11
|
+
subclass.extend ClassMethods
|
12
|
+
subclass.include InstanceMethods
|
29
13
|
end
|
30
14
|
|
31
|
-
attr_reader :
|
32
|
-
alias_method :to_h, :
|
33
|
-
alias_method :to_hash, :
|
15
|
+
attr_reader :attrs
|
16
|
+
alias_method :to_h, :attrs
|
17
|
+
alias_method :to_hash, :attrs
|
34
18
|
|
35
19
|
def initialize(hash = {})
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
20
|
+
unless hash.class <= Hash
|
21
|
+
fail WrongArgument, "[Contextuable ERROR]: `#{self.class}` expects to receive a `Hash` or and object having `Hash` as ancestor."
|
22
|
+
end
|
23
|
+
@attrs = hash
|
24
|
+
@attrs.each do |k, v|
|
40
25
|
define_contextuable_method(k, v)
|
41
26
|
end
|
42
27
|
end
|
43
28
|
|
44
29
|
def [](key)
|
45
|
-
|
30
|
+
attrs[key]
|
46
31
|
end
|
47
32
|
|
48
33
|
def []=(key, value)
|
@@ -50,90 +35,37 @@ class Contextuable
|
|
50
35
|
end
|
51
36
|
|
52
37
|
def method_missing(name, *args, &block)
|
53
|
-
if
|
54
|
-
|
55
|
-
elsif name =~ /\A\w+=\z/
|
56
|
-
value = args.first || block
|
57
|
-
key = name.to_s.gsub('=', '').to_sym
|
58
|
-
set_attribute(key, value)
|
38
|
+
if name =~ /\A\w+=\z/
|
39
|
+
set_attribute_macro(name, *args, &block)
|
59
40
|
else
|
60
|
-
|
61
|
-
|
62
|
-
when /\A\w+_provided\?\z/ then false
|
63
|
-
end
|
41
|
+
out = provided_macro(name)
|
42
|
+
out ? out[:out] : nil
|
64
43
|
end
|
65
44
|
end
|
66
45
|
|
67
46
|
private
|
68
47
|
|
69
|
-
def
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
def define_contextuable_method(key, value)
|
75
|
-
define_singleton_method(key) { args.fetch(key) }
|
76
|
-
define_singleton_method("#{key}_provided?") { true }
|
77
|
-
define_singleton_method("#{key}_not_provided?") { false }
|
78
|
-
end
|
79
|
-
|
80
|
-
def find_in_equivalents(name)
|
81
|
-
found = nil
|
82
|
-
_equivalents.each do |ary|
|
83
|
-
found = ary if ary.include?(name.to_sym)
|
84
|
-
break if found
|
85
|
-
end
|
86
|
-
found
|
48
|
+
def set_attribute_macro(name, *args, &block)
|
49
|
+
value = args.first || block
|
50
|
+
key = name.to_s.gsub('=', '').to_sym
|
51
|
+
set_attribute(key, value)
|
87
52
|
end
|
88
53
|
|
89
|
-
def
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
break if out
|
54
|
+
def provided_macro(name)
|
55
|
+
case name.to_s
|
56
|
+
when /\A\w+_not_provided\?\z/ then { out: true }
|
57
|
+
when /\A\w+_provided\?\z/ then { out: false }
|
94
58
|
end
|
95
|
-
out
|
96
59
|
end
|
97
60
|
|
98
|
-
def
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
def _permitted
|
103
|
-
self.class.instance_variable_get(:@_permitted) || []
|
104
|
-
end
|
105
|
-
|
106
|
-
def _equivalents
|
107
|
-
self.class.instance_variable_get(:@_equivalents) || []
|
108
|
-
end
|
109
|
-
|
110
|
-
def _presence_required
|
111
|
-
self.class.instance_variable_get(:@_presence_required) || []
|
112
|
-
end
|
113
|
-
|
114
|
-
def _defaults
|
115
|
-
self.class.instance_variable_get(:@_defaults) || {}
|
116
|
-
end
|
117
|
-
|
118
|
-
def _required_args
|
119
|
-
self.class.instance_variable_get(:@_required) || []
|
61
|
+
def set_attribute(key, value)
|
62
|
+
attrs[key] = value
|
63
|
+
define_contextuable_method(key, value)
|
120
64
|
end
|
121
65
|
|
122
|
-
def
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
_required_args.map(&:to_sym).each do |r|
|
128
|
-
unless hash.keys.map(&:to_sym).include?(r)
|
129
|
-
fail RequiredFieldNotPresent, "[Contextuable ERROR]: `#{self.class}` expect to be initialized with `#{r}` as an attribute."
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
_presence_required.map(&:to_sym).each do |r|
|
134
|
-
if hash[r].nil?
|
135
|
-
fail PresenceRequired, "[Contextuable ERROR]: `#{self.class}` expects to receive an attribute named `#{r}` not beeing `nil`"
|
136
|
-
end
|
137
|
-
end
|
66
|
+
def define_contextuable_method(key, value)
|
67
|
+
define_singleton_method(key) { attrs.fetch(key) }
|
68
|
+
define_singleton_method("#{key}_provided?") { true }
|
69
|
+
define_singleton_method("#{key}_not_provided?") { false }
|
138
70
|
end
|
139
71
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: contextuable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Artur Pañach
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-04-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -71,6 +71,8 @@ files:
|
|
71
71
|
- bin/setup
|
72
72
|
- contextuable.gemspec
|
73
73
|
- lib/contextuable.rb
|
74
|
+
- lib/contextuable/class_methods.rb
|
75
|
+
- lib/contextuable/instance_methods.rb
|
74
76
|
homepage: https://www.github.com/arturictus/contextuable
|
75
77
|
licenses:
|
76
78
|
- MIT
|
@@ -91,7 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
91
93
|
version: '0'
|
92
94
|
requirements: []
|
93
95
|
rubyforge_project:
|
94
|
-
rubygems_version: 2.
|
96
|
+
rubygems_version: 2.4.6
|
95
97
|
signing_key:
|
96
98
|
specification_version: 4
|
97
99
|
summary: Structs with steroids.
|