hash19 0.0.3 → 0.0.4

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: 2690fb2383e0fb03cf39844a44cee0f8761af48c
4
- data.tar.gz: 430b9b351c64625827b3f4994a8cfed9ca2002ea
3
+ metadata.gz: 8e3af7ef38c2b83b16643922fdb0b9e4f17e9a02
4
+ data.tar.gz: 1ce1e8d0f3355773c09d224ec1e6f8de21afb184
5
5
  SHA512:
6
- metadata.gz: 662633e7af29b3d2eb31dba44e4cc11c2bc615b95dad1b20fa7e566bee0f512180ee1c83bae39d1166fc15d6f7506fd3827a8a7daccd469aca1af9aa07e2976c
7
- data.tar.gz: 7531bcbd9375ccca4fc60fca9b74862192c49296bbedd6bd083ec4c50d1c195357cc354dc5c7f89a6fcd794fc0dcb5e1e2c15e0176f0fe3ce785125b62a1b0bc
6
+ metadata.gz: 5ceb2cc897448d847ab762fd5e63b355962f9b52bd3788c12d5a0451c26bf7b2c30b80d354f08fcbd682a239e84c1282905796dfd950e7e4b9eefa92f50db929
7
+ data.tar.gz: 76740b66f18d888d6630faaa9f5eebf4ce9786f395eece15e87caa09fdee1ab3619e86dc97e6aa628938662e0db810d252165c2a07c8827a0861684d6fe5c431
data/.gitignore CHANGED
@@ -13,3 +13,6 @@
13
13
  *.a
14
14
  mkmf.log
15
15
  .idea
16
+ .gemtags
17
+ .tags
18
+ .tags_sorted_by_file
data/lib/hash19/core.rb CHANGED
@@ -11,7 +11,7 @@ module Hash19
11
11
 
12
12
  module Initializer
13
13
  def initialize(payload={})
14
- if self.class.contains_klass
14
+ if payload.is_a? Array
15
15
  @hash19 = payload.map do |el|
16
16
  klass = resolve_class(self.class.contains_klass.to_s.camelize.singularize)
17
17
  klass.send(:new, el).to_h(lazy: true)
@@ -21,8 +21,11 @@ module Hash19
21
21
  association.map { |hash| klass.send(:new, hash).to_h(lazy: true) }
22
22
  end
23
23
  else
24
- # raise "Key:<#{name}> is not present in #{self.class.name}. Possible specify a trigger" unless
25
- @hash19[opts[:alias] || name] = LazyValue.new(-> { opts[:trigger].call(@hash19.delete(opts[:using])) }) if opts[:trigger]
24
+ puts "warning: Association:<#{name}> is not present in #{self.class.name}. Possible specify a trigger" unless opts[:trigger]
25
+ puts "warning: Key:<#{opts[:using]}> not present in #{self.class.name}. Cannot map association:<#{name}>" unless @hash19.has_key? opts[:using]
26
+ if opts[:trigger] and @hash19.has_key? opts[:using]
27
+ @hash19[opts[:alias] || name] = LazyValue.new(-> { opts[:trigger].call(@hash19.delete(opts[:using])) }) if opts[:trigger]
28
+ end
26
29
  end
27
30
  end
28
31
  end
@@ -38,11 +41,13 @@ module Hash19
38
41
  self.class.injections.each do |opts|
39
42
  async do
40
43
  entries = JsonPath.new(opts[:at]).on(hash).flatten
41
- ids = entries.map { |el| el[opts[:using]] }
44
+ ids = entries.map { |el| el[opts[:using]] }.compact
45
+ next unless ids.present?
42
46
  to_inject = opts[:trigger].call(ids).map(&:with_indifferent_access)
43
47
  key = opts[:as] || opts[:using].to_s.gsub(/_id$|Id$/, '')
44
48
  entries.each do |entry|
45
49
  id = entry.delete(opts[:using])
50
+ next unless id.present?
46
51
  target = to_inject.find { |el| el[opts[:reference] || opts[:using]] == id }
47
52
  entry[key] = target
48
53
  end
@@ -51,12 +56,15 @@ module Hash19
51
56
  end
52
57
  end
53
58
 
54
-
55
59
  def resolve_class(assoc_name)
56
60
  full_class_name = self.class.name
57
61
  new_class = full_class_name.gsub(full_class_name.demodulize, assoc_name)
58
62
  new_class.split('::').inject(Object) do |mod, class_name|
59
- mod.const_get(class_name)
63
+ if mod.const_defined?(class_name)
64
+ mod.const_get(class_name)
65
+ else
66
+ raise("Class:<#{new_class}> not defined! Unable to resolve association:<#{assoc_name.downcase}>")
67
+ end
60
68
  end
61
69
  end
62
70
 
@@ -1,3 +1,3 @@
1
1
  module Hash19
2
- VERSION = '0.0.3'
2
+ VERSION = '0.0.4'
3
3
  end
@@ -2,27 +2,30 @@ require 'spec_helper'
2
2
 
3
3
  describe 'Access Patterns for Hash19' do
4
4
 
5
- class Hash1
6
- include Hash19
7
- attributes :a, :b, :c
8
- end
9
-
10
5
  it 'should be able to access hash keys using dot notation' do
6
+
7
+ class Hash1
8
+ include Hash19
9
+ attributes :a, :b, :c
10
+ end
11
+
11
12
  hash1 = Hash1.new({a: 1, b: 2, c: 3})
12
13
  expect(hash1[:a]).to eq(1)
13
14
  expect(hash1[:b]).to eq(2)
14
15
  expect(hash1[:c]).to eq(3)
15
16
  end
16
17
 
17
- class Hash11
18
- include Hash19
19
- attributes :x, :y
20
- has_one :hash1, alias: :h
21
- end
18
+ it 'should be able to access keys recursively' do
19
+
20
+ class Hash11
21
+ include Hash19
22
+ attributes :x, :y
23
+ has_one :hash1, alias: :h
24
+ end
22
25
 
23
- it 'should be able to work recursively' do
24
26
  hash11 = Hash11.new(hash1: {a: 1, b: 2, c: 3}, x: -1, y: -2)
25
27
  expect(hash11[:h][:a]).to eq(1)
28
+ expect(hash11[:y]).to eq(-2)
26
29
  end
27
30
 
28
31
  end
@@ -21,7 +21,19 @@ describe 'Associations' do
21
21
  expect(parent.to_h).to eq('p' => 1, 'q' => 2, 'child' => {'x' => 1})
22
22
  end
23
23
 
24
- it 'should support key for has_one' do
24
+ it 'should flag error when target class not present' do
25
+ module Computer
26
+ class Laptop < Testable
27
+ attributes :model, :year
28
+ has_one :keyboard
29
+ end
30
+ end
31
+
32
+ expect { Computer::Laptop.new(model: 'MacBook Pro', year: 2013, keyboard: {keys: 101}) }.
33
+ to raise_error('Class:<Computer::Keyboard> not defined! Unable to resolve association:<keyboard>')
34
+ end
35
+
36
+ it 'should support alternate key in payload for has_one' do
25
37
  class OtherParent < Testable
26
38
  attributes :x
27
39
  has_one :child, key: :offspring, class: 'Child'
@@ -31,7 +43,7 @@ describe 'Associations' do
31
43
  expect(parent.to_h).to eq('x' => true, 'child' => {'x' => 1})
32
44
  end
33
45
 
34
- it 'should support alias for has_one' do
46
+ it 'should support association alias for has_one' do
35
47
  class AnotherParent < Testable
36
48
  attributes :x
37
49
  has_one :child, key: :offspring, alias: :junior
@@ -57,7 +69,7 @@ describe 'Associations' do
57
69
  expect(bike.to_h).to eq('cc' => 150, 'wheels' => [{'flat' => false}, {'flat' => true}])
58
70
  end
59
71
 
60
- it 'should support key for has_many' do
72
+ it 'should support alternate key in payload for has_many' do
61
73
  class OtherBike < Testable
62
74
  attributes :cc
63
75
  has_many :wheels, key: :discs
@@ -67,7 +79,7 @@ describe 'Associations' do
67
79
  expect(bike.to_h).to eq('cc' => 150, 'wheels' => [{'flat' => false}, {'flat' => true}])
68
80
  end
69
81
 
70
- it 'should support alias for has_many' do
82
+ it 'should support association alias for has_many' do
71
83
  class AnotherBike < Testable
72
84
  attributes :cc
73
85
  has_many :wheels, key: :discs, alias: :rings
@@ -91,8 +103,8 @@ describe 'Associations' do
91
103
  end
92
104
 
93
105
  it 'should be able to resolve has_many relationship within modules' do
94
- duck = Bird::Duck.new(quack: true, feathers: [{light: true}, {light: true}])
95
- expect(duck.to_h).to eq('quack' => true, 'feathers' => [{'light' => true}, {'light' => true}])
106
+ duck = Bird::Duck.new(quack: true, feathers: [{light: true}, {light: false}])
107
+ expect(duck.to_h).to eq('quack' => true, 'feathers' => [{'light' => true}, {'light' => false}])
96
108
  end
97
109
  end
98
110
 
@@ -132,10 +144,21 @@ describe 'Associations' do
132
144
  it 'should be able to call the trigger on has_one association' do
133
145
  packet = UDPPacket.new(code: 500, error_id: 500)
134
146
  expect(packet.to_h).to eq('code' => 500, 'error_id' => 500, 'all_errors' => [{'error_id' => 500, 'desc' => 'fatal error'},
135
- {'error_id' => 404, 'desc' => 'not found'}])
147
+ {'error_id' => 404, 'desc' => 'not found'}])
136
148
  end
137
149
 
138
150
  end
139
151
 
152
+ context 'no id to lookup' do
153
+ it 'should not fail if association key is not present' do
154
+ class Jedi < Testable
155
+ attributes :name
156
+ has_one :padawan, using: :padawan_id, trigger: ->(id) { Padawan.find }
157
+ end
158
+
159
+ jedi = Jedi.new(name: 'Obi Wan Kenobi')
160
+ expect(jedi.to_h).to eq({"name" => 'Obi Wan Kenobi'})
161
+ end
162
+ end
140
163
 
141
164
  end
@@ -37,5 +37,10 @@ describe 'Containers' do
37
37
  {'name' => 'hulk', 'power' => 'bulk', 'weapon' => {'name' => 'hands', 'id' => 3}}])
38
38
  end
39
39
 
40
+ it 'should not fail when container is empty' do
41
+ super_heroes = SuperHeroes.new([])
42
+ expect(super_heroes.to_h).to eq([])
43
+ end
44
+
40
45
  end
41
46
  end
@@ -12,7 +12,6 @@ describe Hash19::Core do
12
12
  attributes :a, :b, :c
13
13
  end
14
14
 
15
-
16
15
  it 'should be able to assign whitelisted attributes' do
17
16
  test = Test1.new(a: 1, b: 2, d: 4)
18
17
  expect(test.to_h).to eq('a' => 1, 'b' => 2)
@@ -23,32 +22,40 @@ describe Hash19::Core do
23
22
  expect(test.to_h).to eq({})
24
23
  end
25
24
 
26
- end
27
-
28
- context 'Single attribute and aliases' do
29
-
30
- class Test2 < Testable
31
- attributes :a, :b, :c
32
- attribute :fake, key: :actual
33
- attribute :d
25
+ it 'should not break when an empty hash is passed' do
26
+ test = Test1.new({})
27
+ expect(test.to_h).to eq({})
34
28
  end
35
29
 
36
- it 'should be able to assign attributes based on alias' do
37
- test = Test2.new(actual: 1)
38
- expect(test.to_h).to eq('fake' => 1)
30
+ it 'should not break when an empty array is passed' do
31
+ test = Test1.new([])
32
+ expect(test.to_h).to eq([])
39
33
  end
40
34
 
41
- it 'should be able to use both attribute and attributes constructs' do
42
- test = Test2.new(actual: 1, a: 2, d: 3)
43
- expect(test.to_h).to eq('fake' => 1, 'a' => 2, 'd' => 3)
44
- end
35
+ end
45
36
 
46
- it 'should ignore alias if key not present' do
47
- test = Test2.new(a: 2)
48
- expect(test.to_h).to eq('a' => 2)
49
- end
37
+ context 'Single attribute and aliases' do
38
+
39
+ class Test2 < Testable
40
+ attributes :a, :b, :c
41
+ attribute :fake, key: :actual
42
+ attribute :d
43
+ end
44
+
45
+ it 'should be able to assign attributes based on alias' do
46
+ test = Test2.new(actual: 1)
47
+ expect(test.to_h).to eq('fake' => 1)
50
48
  end
51
49
 
50
+ it 'should be able to use both attribute and attributes constructs' do
51
+ test = Test2.new(actual: 1, a: 2, d: 3)
52
+ expect(test.to_h).to eq('fake' => 1, 'a' => 2, 'd' => 3)
53
+ end
52
54
 
55
+ it 'should ignore alias if key not present' do
56
+ test = Test2.new(a: 2)
57
+ expect(test.to_h).to eq('a' => 2)
58
+ end
59
+ end
53
60
 
54
61
  end
@@ -36,6 +36,27 @@ describe 'Injections' do
36
36
  {'name' => 'Kanpai', 'eats' => {'id' => 3, 'name' => 'orange'}}
37
37
  ])
38
38
  end
39
+
40
+ it "should not fail when no keys for injection present" do
41
+ gru_team = SuperVillain.new(name: 'Gru', minions: [{name: 'Poppadom'},
42
+ {name: 'Gelato'},
43
+ {name: 'Kanpai'}])
44
+ expect(gru_team.to_h).to eq('name' => 'Gru', 'minions' => [{'name' => 'Poppadom'},
45
+ {'name' => 'Gelato'},
46
+ {'name' => 'Kanpai'}
47
+ ])
48
+ end
49
+
50
+ it "should only map associations with keys" do
51
+ gru_team = SuperVillain.new(name: 'Gru', minions: [{name: 'Poppadom', fruit_id: 1},
52
+ {name: 'Gelato'},
53
+ {name: 'Kanpai'}])
54
+ expect(gru_team.to_h).to eq('name' => 'Gru', 'minions' => [{'name' => 'Poppadom', 'eats' => {'id' => 1, 'name' => 'banana'}},
55
+ {'name' => 'Gelato'},
56
+ {'name' => 'Kanpai'}
57
+ ])
58
+ end
59
+
39
60
  end
40
61
 
41
62
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hash19
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - RC
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-12 00:00:00.000000000 Z
11
+ date: 2014-12-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler