config_mapper 0.2.0 → 1.0.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 +53 -43
- data/lib/config_mapper.rb +4 -78
- data/lib/config_mapper/attribute_sink.rb +42 -0
- data/lib/config_mapper/error_proxy.rb +23 -0
- data/lib/config_mapper/object_as_hash.rb +29 -0
- data/lib/config_mapper/version.rb +2 -2
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a927800ba901de2ba648d012936b19b591d24c5e
|
4
|
+
data.tar.gz: c93aace56fd8a8a9662f547ef72e5c5f1d0a9396
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5da46b8fb08d97ccfe985cb2a0da607de151f2d70167c0edd03c66a5771d9e5e24fda1a2183e58552103aa451d9016c8d45991ba87d1c3a47fc0b3e1e7b0e8e1
|
7
|
+
data.tar.gz: 3b40a4cc5c9049f681bbeaf17cacad8817dffd48c53b5ec46314a1e49f0410053f335feee942357b8265dbbb660468751f2de1657994af68bca3b4514399faaf
|
data/README.md
CHANGED
@@ -6,74 +6,84 @@ ConfigMapper maps configuration data onto Ruby objects.
|
|
6
6
|
|
7
7
|
Imagine you have some Ruby objects:
|
8
8
|
|
9
|
-
|
9
|
+
```ruby
|
10
|
+
class Position
|
10
11
|
|
11
|
-
|
12
|
-
|
12
|
+
attr_reader :x
|
13
|
+
attr_reader :y
|
13
14
|
|
14
|
-
|
15
|
-
|
15
|
+
def x=(arg); @x = Integer(arg); end
|
16
|
+
def y=(arg); @y = Integer(arg); end
|
16
17
|
|
17
|
-
|
18
|
+
end
|
18
19
|
|
19
|
-
|
20
|
+
class State
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
22
|
+
def initialize
|
23
|
+
@position = Position.new
|
24
|
+
end
|
24
25
|
|
25
|
-
|
26
|
-
|
26
|
+
attr_reader :position
|
27
|
+
attr_accessor :orientation
|
27
28
|
|
28
|
-
|
29
|
+
end
|
29
30
|
|
30
|
-
|
31
|
+
state = State.new
|
32
|
+
```
|
31
33
|
|
32
34
|
and wish to populate/modify it, based on plain data:
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
36
|
+
```ruby
|
37
|
+
config_data = {
|
38
|
+
"orientation" => "North",
|
39
|
+
"position" => {
|
40
|
+
"x" => 2,
|
41
|
+
"y" => 4
|
42
|
+
}
|
43
|
+
}
|
44
|
+
```
|
41
45
|
|
42
46
|
ConfigMapper will help you out:
|
43
47
|
|
44
|
-
|
48
|
+
```ruby
|
49
|
+
require 'config_mapper'
|
45
50
|
|
46
|
-
|
47
|
-
|
48
|
-
|
51
|
+
errors = ConfigMapper.set(config_data, state)
|
52
|
+
state.orientation #=> "North"
|
53
|
+
state.position.x #=> 2
|
54
|
+
```
|
49
55
|
|
50
56
|
It can even populate Hashes of objects, e.g.
|
51
57
|
|
52
|
-
|
58
|
+
```ruby
|
59
|
+
positions = Hash.new { |h,k| h[k] = Position.new }
|
53
60
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
61
|
+
config_data = {
|
62
|
+
"fred" => { "x" => 2, "y" => 4 },
|
63
|
+
"mary" => { "x" => 3, "y" => 5 }
|
64
|
+
}
|
58
65
|
|
59
|
-
|
60
|
-
|
61
|
-
|
66
|
+
ConfigMapper.set(config_data, positions)
|
67
|
+
positions["fred"].x #=> 2
|
68
|
+
positions["mary"].y #=> 5
|
69
|
+
```
|
62
70
|
|
63
71
|
### Errors
|
64
72
|
|
65
73
|
`ConfigMapper.set` returns a Hash of errors encountered while mapping data
|
66
74
|
onto objects. The errors are Exceptions (typically ArgumentError or NoMethodError),
|
67
|
-
keyed by a
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
75
|
+
keyed by a Array representing the path to the offending data. e.g.
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
config_data = {
|
79
|
+
"position" => {
|
80
|
+
"bogus" => "flibble"
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
errors = ConfigMapper.set(config_data, state)
|
85
|
+
errors #=> { ["position", "bogus"] => #<NoMethodError> }
|
86
|
+
```
|
77
87
|
|
78
88
|
## License
|
79
89
|
|
data/lib/config_mapper.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
require "config_mapper/attribute_sink"
|
2
|
+
|
1
3
|
# Supports marshalling of plain-old data (e.g. loaded from
|
2
4
|
# YAML files) onto strongly-typed objects.
|
3
5
|
#
|
4
|
-
|
6
|
+
module ConfigMapper
|
5
7
|
|
6
8
|
# Attempt to set attributes on a target object.
|
7
9
|
#
|
@@ -13,85 +15,9 @@ class ConfigMapper
|
|
13
15
|
# @return [Hash] exceptions encountered
|
14
16
|
#
|
15
17
|
def self.set(data, target)
|
16
|
-
mapper = new(target)
|
18
|
+
mapper = AttributeSink.new(target)
|
17
19
|
mapper.set_attributes(data)
|
18
20
|
mapper.errors
|
19
21
|
end
|
20
22
|
|
21
|
-
def initialize(target, errors = {})
|
22
|
-
@target = ObjectAsHash[target]
|
23
|
-
@errors = errors
|
24
|
-
end
|
25
|
-
|
26
|
-
attr_reader :target
|
27
|
-
attr_reader :errors
|
28
|
-
|
29
|
-
# Set multiple attributes from a Hash.
|
30
|
-
#
|
31
|
-
def set_attributes(data)
|
32
|
-
data.each do |key, value|
|
33
|
-
set_attribute(key, value)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
private
|
38
|
-
|
39
|
-
# Set a single attribute.
|
40
|
-
#
|
41
|
-
def set_attribute(key, value)
|
42
|
-
if value.is_a?(Hash) && !target[key].nil?
|
43
|
-
nested_errors = ErrorProxy.new(errors, "#{key}.")
|
44
|
-
nested_mapper = self.class.new(target[key], nested_errors)
|
45
|
-
nested_mapper.set_attributes(value)
|
46
|
-
else
|
47
|
-
target[key] = value
|
48
|
-
end
|
49
|
-
rescue NoMethodError, ArgumentError => e
|
50
|
-
errors[key] = e
|
51
|
-
end
|
52
|
-
|
53
|
-
class ObjectAsHash
|
54
|
-
|
55
|
-
def self.[](target)
|
56
|
-
if target.is_a?(Hash)
|
57
|
-
target
|
58
|
-
else
|
59
|
-
ObjectAsHash.new(target)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def initialize(target)
|
64
|
-
@target = target
|
65
|
-
end
|
66
|
-
|
67
|
-
def [](key)
|
68
|
-
@target.public_send(key)
|
69
|
-
end
|
70
|
-
|
71
|
-
def []=(key, value)
|
72
|
-
@target.public_send("#{key}=", value)
|
73
|
-
end
|
74
|
-
|
75
|
-
end
|
76
|
-
|
77
|
-
# Wraps a Hash of errors, injecting prefixes
|
78
|
-
#
|
79
|
-
class ErrorProxy
|
80
|
-
|
81
|
-
def initialize(errors, prefix)
|
82
|
-
@errors = errors
|
83
|
-
@prefix = prefix
|
84
|
-
end
|
85
|
-
|
86
|
-
def []=(key, value)
|
87
|
-
errors[prefix + key] = value
|
88
|
-
end
|
89
|
-
|
90
|
-
private
|
91
|
-
|
92
|
-
attr_reader :errors
|
93
|
-
attr_reader :prefix
|
94
|
-
|
95
|
-
end
|
96
|
-
|
97
23
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "config_mapper/error_proxy"
|
2
|
+
require "config_mapper/object_as_hash"
|
3
|
+
|
4
|
+
module ConfigMapper
|
5
|
+
|
6
|
+
# Sets attributes on an object, collecting errors
|
7
|
+
#
|
8
|
+
class AttributeSink
|
9
|
+
|
10
|
+
def initialize(target, errors = {})
|
11
|
+
@target = ObjectAsHash[target]
|
12
|
+
@errors = errors
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :target
|
16
|
+
attr_reader :errors
|
17
|
+
|
18
|
+
# Set multiple attributes from a Hash.
|
19
|
+
#
|
20
|
+
def set_attributes(data)
|
21
|
+
data.each do |key, value|
|
22
|
+
set_attribute(key, value)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Set a single attribute.
|
27
|
+
#
|
28
|
+
def set_attribute(key, value)
|
29
|
+
if value.is_a?(Hash) && !target[key].nil?
|
30
|
+
nested_errors = ErrorProxy.new(errors, [key])
|
31
|
+
nested_mapper = self.class.new(target[key], nested_errors)
|
32
|
+
nested_mapper.set_attributes(value)
|
33
|
+
else
|
34
|
+
target[key] = value
|
35
|
+
end
|
36
|
+
rescue NoMethodError, ArgumentError => e
|
37
|
+
errors[[key]] = e
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ConfigMapper
|
2
|
+
|
3
|
+
# Wraps a Hash of errors, injecting prefixes
|
4
|
+
#
|
5
|
+
class ErrorProxy
|
6
|
+
|
7
|
+
def initialize(errors, prefix)
|
8
|
+
@errors = errors
|
9
|
+
@prefix = prefix
|
10
|
+
end
|
11
|
+
|
12
|
+
def []=(key, value)
|
13
|
+
errors[prefix + key] = value
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
attr_reader :errors
|
19
|
+
attr_reader :prefix
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ConfigMapper
|
2
|
+
|
3
|
+
# Wrap an object to make it look more like a Hash.
|
4
|
+
#
|
5
|
+
class ObjectAsHash
|
6
|
+
|
7
|
+
def self.[](target)
|
8
|
+
if target.is_a?(Hash)
|
9
|
+
target
|
10
|
+
else
|
11
|
+
ObjectAsHash.new(target)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(target)
|
16
|
+
@target = target
|
17
|
+
end
|
18
|
+
|
19
|
+
def [](key)
|
20
|
+
@target.public_send(key)
|
21
|
+
end
|
22
|
+
|
23
|
+
def []=(key, value)
|
24
|
+
@target.public_send("#{key}=", value)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: config_mapper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-09-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -69,6 +69,9 @@ files:
|
|
69
69
|
- Rakefile
|
70
70
|
- config_mapper.gemspec
|
71
71
|
- lib/config_mapper.rb
|
72
|
+
- lib/config_mapper/attribute_sink.rb
|
73
|
+
- lib/config_mapper/error_proxy.rb
|
74
|
+
- lib/config_mapper/object_as_hash.rb
|
72
75
|
- lib/config_mapper/version.rb
|
73
76
|
homepage: https://github.com/mdub/config_mapper
|
74
77
|
licenses:
|
@@ -90,7 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
90
93
|
version: '0'
|
91
94
|
requirements: []
|
92
95
|
rubyforge_project:
|
93
|
-
rubygems_version: 2.4.
|
96
|
+
rubygems_version: 2.4.8
|
94
97
|
signing_key:
|
95
98
|
specification_version: 4
|
96
99
|
summary: Maps config data onto plain old objects
|