aduki 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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