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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7d643ab8607c785459650363209b078699513bd5
4
- data.tar.gz: 1a4ef25c93114686800bc0cf82dc13c7736e448a
3
+ metadata.gz: a927800ba901de2ba648d012936b19b591d24c5e
4
+ data.tar.gz: c93aace56fd8a8a9662f547ef72e5c5f1d0a9396
5
5
  SHA512:
6
- metadata.gz: f323e289fbdc9d7c1f6d8f8c436e7d62bb68b98b35268e210a0f4bc0568a6f69549e7c9fb54c38173ce3b84f797c5dba732a7ab80239b0ccaf4d046bbbca5278
7
- data.tar.gz: 7fcb8808ee09efb2a932ab5b8f4dc74f49405b12438c50428d2506667a7f5862b31b2a771e08964f49ed8f9d8988355748328c407a80eb376f5ff40ec5a19daf
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
- class Position
9
+ ```ruby
10
+ class Position
10
11
 
11
- attr_reader :x
12
- attr_reader :y
12
+ attr_reader :x
13
+ attr_reader :y
13
14
 
14
- def x=(arg); @x = Integer(arg); end
15
- def y=(arg); @y = Integer(arg); end
15
+ def x=(arg); @x = Integer(arg); end
16
+ def y=(arg); @y = Integer(arg); end
16
17
 
17
- end
18
+ end
18
19
 
19
- class State
20
+ class State
20
21
 
21
- def initialize
22
- @position = Position.new
23
- end
22
+ def initialize
23
+ @position = Position.new
24
+ end
24
25
 
25
- attr_reader :position
26
- attr_accessor :orientation
26
+ attr_reader :position
27
+ attr_accessor :orientation
27
28
 
28
- end
29
+ end
29
30
 
30
- state = State.new
31
+ state = State.new
32
+ ```
31
33
 
32
34
  and wish to populate/modify it, based on plain data:
33
35
 
34
- config_data = {
35
- "orientation" => "North",
36
- "position" => {
37
- "x" => 2,
38
- "y" => 4
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
- require 'config_mapper'
48
+ ```ruby
49
+ require 'config_mapper'
45
50
 
46
- errors = ConfigMapper.set(config_data, state)
47
- state.orientation #=> "North"
48
- state.position.x #=> 2
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
- positions = Hash.new { |h,k| h[k] = Position.new }
58
+ ```ruby
59
+ positions = Hash.new { |h,k| h[k] = Position.new }
53
60
 
54
- config_data = {
55
- "fred" => { "x" => 2, "y" => 4 },
56
- "mary" => { "x" => 3, "y" => 5 }
57
- }
61
+ config_data = {
62
+ "fred" => { "x" => 2, "y" => 4 },
63
+ "mary" => { "x" => 3, "y" => 5 }
64
+ }
58
65
 
59
- ConfigMapper.set(config_data, positions)
60
- positions["fred"].x #=> 2
61
- positions["mary"].y #=> 5
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 dot-delimited path to the offending data. e.g.
68
-
69
- config_data = {
70
- "position" => {
71
- "bogus" => "flibble"
72
- }
73
- }
74
-
75
- errors = ConfigMapper.set(config_data, state)
76
- errors #=> { "position.bogus" => #<NoMethodError> }
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
 
@@ -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
- class ConfigMapper
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
@@ -1,5 +1,5 @@
1
- class ConfigMapper
1
+ module ConfigMapper
2
2
 
3
- VERSION = "0.2.0"
3
+ VERSION = "1.0.0"
4
4
 
5
5
  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.2.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-08-04 00:00:00.000000000 Z
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.5
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