aduki 0.0.4 → 0.0.5

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/README.md CHANGED
@@ -48,6 +48,7 @@ Here's an abbreviated version:
48
48
  attr_accessor :name, :weight, :speed, :builder, :team
49
49
  attr_accessor :assemblies, :dimensions
50
50
  aduki :assemblies => Assembly, :builder => MachineBuilder
51
+ aduki :helpers => { :key => MachineBuilder }
51
52
  end
52
53
 
53
54
  class Model
@@ -71,6 +72,13 @@ This line instructs aduki to initialise the #gadget field with a Gadget object.
71
72
  array with a Machine object. Aduki decides to create an object or an array of objects depending on the attributes-hash contents, rather than on any
72
73
  metadata you may specify here.
73
74
 
75
+
76
+ The following line tells aduki to expect a hash for the #helpers attribute, and for each value in the hash is should construct a new MachineBuilder instance:
77
+
78
+ aduki :helpers => { :key => MachineBuilder }
79
+
80
+
81
+
74
82
  ## Contributing
75
83
 
76
84
  1. Fork it
@@ -17,6 +17,7 @@ Gem::Specification.new do |gem|
17
17
 
18
18
 
19
19
  gem.add_development_dependency 'rspec', '~> 2.9'
20
+ gem.add_development_dependency 'rspec_numbering_formatter'
20
21
 
21
22
  gem.files = `git ls-files`.split($/)
22
23
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
@@ -1,30 +1,71 @@
1
1
  require "aduki/version"
2
2
 
3
3
  module Aduki
4
+ def self.to_aduki obj, collector={ }, key="", join=""
5
+ case obj
6
+ when Hash
7
+ obj.keys.inject(collector) { |result, k|
8
+ v = obj[k]
9
+ to_aduki v, collector, "#{key}#{join}#{k}", "."
10
+ result
11
+ }
12
+ when Array
13
+ obj.each_with_index do |av, ix|
14
+ to_aduki av, collector, "#{key}[#{ix}]", "."
15
+ end
16
+ when String, Numeric, Symbol
17
+ collector[key] = obj
18
+ else
19
+ vv = obj.instance_variables
20
+ vv.each do |v|
21
+ accessor = v.to_s.gsub(/^@/, "").to_sym
22
+ if obj.respond_to?(accessor) && obj.respond_to?("#{accessor}=".to_sym)
23
+ to_aduki obj.send(accessor), collector, "#{key}#{join}#{accessor}", "."
24
+ end
25
+ end
26
+ end
27
+ collector
28
+ end
29
+
4
30
  def self.to_value klass, setter, value
5
31
  type = klass.aduki_type_for_attribute_name setter
6
- type ? type.new(value) : value
32
+ if type.is_a? Hash
33
+ to_typed_hash type.values.first, value
34
+ else
35
+ type ? type.new(value) : value
36
+ end
7
37
  end
8
38
 
9
- def self.apply_attributes object, attrs
10
- setters = { }
11
- klass = object.class
39
+ def self.to_typed_hash klass, value
40
+ setters = split_attributes value
41
+ hsh = { }
42
+ setters.each { |k, v|
43
+ hsh[k] = klass.new(v)
44
+ }
45
+ hsh
46
+ end
12
47
 
48
+ def self.split_attributes attrs
49
+ setters = { }
13
50
  attrs.each do |setter, value|
14
- if setter.match /\./
51
+ if setter.match(/\./)
15
52
  first, rest = setter.split(/\./, 2)
16
53
  setters[first] ||= { }
17
54
  setters[first][rest] = value
18
- elsif setter.match /\[\d+\]/
19
- setters[setter] = value
20
55
  else
21
- object.send "#{setter}=", value
56
+ setters[setter] = value
22
57
  end
23
58
  end
59
+ setters
60
+ end
61
+
62
+ def self.apply_attributes object, attrs
63
+ setters = split_attributes attrs
64
+ klass = object.class
24
65
 
25
66
  setters.each do |setter, value|
26
- if setter.match /\[\d+\]/
27
- setter = setter.gsub /\[\d+\]/, ''
67
+ if setter.match(/\[\d+\]/)
68
+ setter = setter.gsub(/\[\d+\]/, '')
28
69
  array = object.send setter.to_sym
29
70
  if array == nil
30
71
  array = []
@@ -32,7 +73,6 @@ module Aduki
32
73
  end
33
74
  array << to_value(klass, setter, value)
34
75
  else
35
- type = klass.aduki_type_for_attribute_name setter
36
76
  object.send "#{setter}=", to_value(klass, setter, value)
37
77
  end
38
78
  end
@@ -1,3 +1,3 @@
1
1
  module Aduki
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -35,6 +35,18 @@ describe Aduki::Initializer do
35
35
  "machines[0].team.lead" => "Shakespeare", # there is no class definition for #team, so Aduki will apply a hash with properties #lead, #code, #design
36
36
  "machines[0].team.code" => "Chaucer",
37
37
  "machines[0].team.design" => "Jobs",
38
+ "machines[0].helpers.jim.name" => "Jim Appleby",
39
+ "machines[0].helpers.jim.email" => "Jim.Appleby@example.com",
40
+ "machines[0].helpers.jim.phone" => "123 456 789",
41
+ "machines[0].helpers.jim.office" => "Elephant & Castle",
42
+ "machines[0].helpers.ben.name" => "Ben Barnes",
43
+ "machines[0].helpers.ben.email" => "Ben.Barnes@example.com",
44
+ "machines[0].helpers.ben.phone" => "123 456 790",
45
+ "machines[0].helpers.ben.office" => "Cockney",
46
+ "machines[0].helpers.pat.name" => "Patrick O'Brien",
47
+ "machines[0].helpers.pat.email" => "Patrick.O.Brien@example.com",
48
+ "machines[0].helpers.pat.phone" => "123 456 791",
49
+ "machines[0].helpers.pat.office" => "Hammersmith",
38
50
  "machines[1].name" => "The Second Machine",
39
51
  "machines[1].weight" => "34",
40
52
  "machines[1].speed" => "289",
@@ -104,6 +116,21 @@ describe Aduki::Initializer do
104
116
  model.machines[0].dimensions[2].should == "3859.39"
105
117
  model.machines[0].dimensions[3].should == "2365.68"
106
118
  model.machines[0].team.should == { "lead" => "Shakespeare", "code" => "Chaucer", "design" => "Jobs"}
119
+ model.machines[0].helpers["jim"].should be_a MachineBuilder
120
+ model.machines[0].helpers["jim"].name.should == "Jim Appleby"
121
+ model.machines[0].helpers["jim"].email.should == "Jim.Appleby@example.com"
122
+ model.machines[0].helpers["jim"].phone.should == "123 456 789"
123
+ model.machines[0].helpers["jim"].office.should == "Elephant & Castle"
124
+ model.machines[0].helpers["ben"].should be_a MachineBuilder
125
+ model.machines[0].helpers["ben"].name.should == "Ben Barnes"
126
+ model.machines[0].helpers["ben"].email.should == "Ben.Barnes@example.com"
127
+ model.machines[0].helpers["ben"].phone.should == "123 456 790"
128
+ model.machines[0].helpers["ben"].office.should == "Cockney"
129
+ model.machines[0].helpers["pat"].should be_a MachineBuilder
130
+ model.machines[0].helpers["pat"].name.should == "Patrick O'Brien"
131
+ model.machines[0].helpers["pat"].email.should == "Patrick.O.Brien@example.com"
132
+ model.machines[0].helpers["pat"].phone.should == "123 456 791"
133
+ model.machines[0].helpers["pat"].office.should == "Hammersmith"
107
134
  model.machines[1].name.should == "The Second Machine"
108
135
  model.machines[1].weight.should == "34"
109
136
  model.machines[1].speed.should == "289"
@@ -138,5 +165,36 @@ describe Aduki::Initializer do
138
165
  model.countries[2].should == "Germany"
139
166
  model.countries[3].should == "Ireland"
140
167
  model.countries[4].should == "Spain"
168
+
169
+ sensibly_indexed_props = props.merge({
170
+ "machines[1].assemblies[0].name" => "second machine, first assembly", # the array index distinguishes items but does not order them
171
+ "machines[1].assemblies[0].colour" => "purple",
172
+ "machines[1].assemblies[0].size" => "pretty small",
173
+ "machines[1].assemblies[1].name" => "second machine, second assembly",
174
+ "machines[1].assemblies[1].colour" => "turquoise",
175
+ "machines[1].assemblies[1].size" => "large-ish",
176
+ "machines[1].assemblies[2].name" => "second machine, third assembly",
177
+ "machines[1].assemblies[2].colour" => "magenta",
178
+ "machines[1].assemblies[2].size" => "gigantic",
179
+ "machines[1].dimensions[0]" => "1985.85",
180
+ "machines[1].dimensions[1]" => "7234.92",
181
+ "machines[1].dimensions[2]" => "9725.52",
182
+ "machines[1].dimensions[3]" => "3579.79",
183
+ })
184
+
185
+ silly_keys = [ "machines[1].assemblies[98].name",
186
+ "machines[1].assemblies[98].colour",
187
+ "machines[1].assemblies[98].size",
188
+ "machines[1].assemblies[99].name",
189
+ "machines[1].assemblies[99].colour",
190
+ "machines[1].assemblies[99].size",
191
+ "machines[1].dimensions[20]",
192
+ "machines[1].dimensions[30]",
193
+ "machines[1].dimensions[40]",
194
+ "machines[1].dimensions[50]"]
195
+
196
+ silly_keys.each { |k| sensibly_indexed_props.delete k }
197
+
198
+ Aduki.to_aduki(model).should == sensibly_indexed_props
141
199
  end
142
200
  end
@@ -28,8 +28,9 @@ end
28
28
  class Machine
29
29
  include Aduki::Initializer
30
30
  attr_accessor :name, :weight, :speed, :builder, :team
31
- attr_accessor :assemblies, :dimensions
31
+ attr_accessor :assemblies, :dimensions, :helpers
32
32
  aduki :assemblies => Assembly, :builder => MachineBuilder
33
+ aduki :helpers => { :key => MachineBuilder }
33
34
  end
34
35
 
35
36
  class Model
@@ -0,0 +1,115 @@
1
+ require "aduki"
2
+ require "spec_helper"
3
+
4
+ describe Aduki do
5
+ it "should return a plain hash structure" do
6
+ hsh = { "foo" => "bar" }
7
+ props = Aduki.to_aduki hsh
8
+ props.should == { "foo" => "bar" }
9
+ end
10
+
11
+ it "should flatten nested keys" do
12
+ hsh = { "foo" => "bar", "bing" => { "boo" => "wogga", "tingle" => "wimp" } }
13
+ props = Aduki.to_aduki hsh
14
+ props.should == {
15
+ "foo" => "bar",
16
+ "bing.boo" => "wogga",
17
+ "bing.tingle" => "wimp"
18
+ }
19
+ end
20
+
21
+ it "should flatten deeply nested keys" do
22
+ hsh = {
23
+ "foo" => "bar",
24
+ "bing" => {
25
+ "boo" => "wogga",
26
+ "tingle" => "wimp",
27
+ "harpoon" => {
28
+ "shonk" => "twaddle",
29
+ "scorn" => "shart"
30
+ }} }
31
+ props = Aduki.to_aduki hsh
32
+ props.should == {
33
+ "foo" => "bar",
34
+ "bing.boo" => "wogga",
35
+ "bing.tingle" => "wimp",
36
+ "bing.harpoon.shonk" => "twaddle",
37
+ "bing.harpoon.scorn" => "shart",
38
+ }
39
+ end
40
+
41
+ it "should flatten array keys also " do
42
+ hsh = {
43
+ "foo" => "bar",
44
+ "bing" => {
45
+ "boo" => "wogga",
46
+ "tingle" => "wimp",
47
+ "harpoon" => ["shonk",
48
+ "twaddle",
49
+ "scorn",
50
+ "shart" ]
51
+ } }
52
+ props = Aduki.to_aduki hsh
53
+ props.should == {
54
+ "foo" => "bar",
55
+ "bing.boo" => "wogga",
56
+ "bing.tingle" => "wimp",
57
+ "bing.harpoon[0]" => "shonk",
58
+ "bing.harpoon[1]" => "twaddle",
59
+ "bing.harpoon[2]" => "scorn",
60
+ "bing.harpoon[3]" => "shart",
61
+ }
62
+ end
63
+
64
+ it "should flatten nested arrays " do
65
+ hsh = {
66
+ "foo" => "bar",
67
+ "bing" => {
68
+ "boo" => "wogga",
69
+ "tingle" => "wimp",
70
+ "harpoon" => ["shonk",
71
+ "twaddle",
72
+ %w{alpha beta gamma},
73
+ { wing: :tip, tail: :fin } ]
74
+ } }
75
+ props = Aduki.to_aduki hsh
76
+ props.should == {
77
+ "foo" => "bar",
78
+ "bing.boo" => "wogga",
79
+ "bing.tingle" => "wimp",
80
+ "bing.harpoon[0]" => "shonk",
81
+ "bing.harpoon[1]" => "twaddle",
82
+ "bing.harpoon[2][0]" => "alpha",
83
+ "bing.harpoon[2][1]" => "beta",
84
+ "bing.harpoon[2][2]" => "gamma",
85
+ "bing.harpoon[3].wing" => :tip,
86
+ "bing.harpoon[3].tail" => :fin,
87
+ }
88
+ end
89
+
90
+ it "should flatten aduki objects " do
91
+ hsh = {
92
+ "foo" => "bar",
93
+ "bing" => {
94
+ "boo" => "wogga",
95
+ "tingle" => "wimp",
96
+ "harpoon" => ["shonk",
97
+ "twaddle",
98
+ %w{alpha beta gamma},
99
+ { wing: :tip, tail: :fin } ]
100
+ } }
101
+ props = Aduki.to_aduki hsh
102
+ props.should == {
103
+ "foo" => "bar",
104
+ "bing.boo" => "wogga",
105
+ "bing.tingle" => "wimp",
106
+ "bing.harpoon[0]" => "shonk",
107
+ "bing.harpoon[1]" => "twaddle",
108
+ "bing.harpoon[2][0]" => "alpha",
109
+ "bing.harpoon[2][1]" => "beta",
110
+ "bing.harpoon[2][2]" => "gamma",
111
+ "bing.harpoon[3].wing" => :tip,
112
+ "bing.harpoon[3].tail" => :fin,
113
+ }
114
+ end
115
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aduki
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-15 00:00:00.000000000 Z
12
+ date: 2013-12-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -27,6 +27,22 @@ dependencies:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
29
  version: '2.9'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec_numbering_formatter
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
30
46
  description: recursive attribute setting for ruby objects
31
47
  email:
32
48
  - conan@conandalton.net
@@ -46,6 +62,7 @@ files:
46
62
  - spec/initializer_spec.rb
47
63
  - spec/model.rb
48
64
  - spec/spec_helper.rb
65
+ - spec/to_aduki_spec.rb
49
66
  homepage: https://github.com/conanite/aduki
50
67
  licenses:
51
68
  - MIT
@@ -75,3 +92,4 @@ test_files:
75
92
  - spec/initializer_spec.rb
76
93
  - spec/model.rb
77
94
  - spec/spec_helper.rb
95
+ - spec/to_aduki_spec.rb