objectifyhash 2.3.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 725c8e28f27aa16476e95d07b9ee76389db8c3e2
4
+ data.tar.gz: 1324184f85b193430984b55e8fb8077056fc15f2
5
+ SHA512:
6
+ metadata.gz: d561bb269d84025f9ace330065e74b457533b62dee1efdbd31b72cba18b19228ca83c6ab2c84713188e528f11040a9165838a70cb4eb6e74602dfd6fd0c5dad0
7
+ data.tar.gz: 8255df63d8336618e2e1195b048b8ceafe3a0603bb8f9afb8a520304124448cd5b8ec9121b1e1dcc9610d5408f92db95a739b5daaedaf94df6624bbfa19f4556
data/License.txt ADDED
@@ -0,0 +1,12 @@
1
+ Copyright (c) 2016, Sky UK Limited
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
+
6
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7
+
8
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
9
+
10
+ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,158 @@
1
+ # coding: utf-8
2
+
3
+ module ObjectifyHash
4
+ alias_method :eql?, :==
5
+ attr_accessor :values_to_compare
6
+
7
+ EXCEPTIONS = {
8
+ data: Proc.new do | value | value; end
9
+ }
10
+ NULLABLE_KEYS = []
11
+
12
+ class GenericObject
13
+ include ObjectifyHash
14
+
15
+ def initialize hash
16
+ convert_and_define hash
17
+ end
18
+
19
+ end
20
+
21
+
22
+ def convert_and_define hash
23
+ @original_hash = hash
24
+ @values_to_compare||=[]
25
+ @original_hash.each do |key, value|
26
+ key = 'klass' if key == 'class'
27
+ key = key.to_sym
28
+ case
29
+ when key == :id
30
+ set :guid, value
31
+ when key == :method
32
+ set :verb, value
33
+ when EXCEPTIONS.key?( key )
34
+ set key, EXCEPTIONS[ key ].call( value )
35
+ when value.is_a?(Hash)
36
+ klass = get_new_class key
37
+ # puts "Going to instanciate class based on #{key}"
38
+ object = klass.new( value )
39
+ # puts 'success'
40
+ set key, object
41
+ when value.is_a?(Array)
42
+ set key, objectify_array(value, key)
43
+ else
44
+ set key, value
45
+ end
46
+ end
47
+
48
+ NULLABLE_KEYS.each do |key|
49
+ unless self.respond_to?( key )
50
+ set key, nil
51
+ end
52
+ end
53
+
54
+ end
55
+
56
+
57
+ def objectify_array array,name
58
+ array.map do |elem|
59
+ if EXCEPTIONS.key? name
60
+ EXCEPTIONS[ name ].call( elem )
61
+ else
62
+ if elem.is_a? Hash
63
+ klass = get_new_class name.to_s.sub(/s$/, '').to_sym
64
+ klass.new elem
65
+ else
66
+ elem
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ def get_new_class name
73
+ name = "#{name.capitalize}_".to_sym if Object.constants.include? name.capitalize.to_sym
74
+ self.class.const_defined?(name.capitalize) ?
75
+ self.class.const_get(name.capitalize) :
76
+ self.class.const_set(name.capitalize, ObjectifyHash::GenericObject)
77
+ end
78
+
79
+
80
+ def set key, value
81
+ method_name = Object.instance_methods.include?( key ) ? :"_#{key}_" : key.to_sym
82
+ @values_to_compare.push method_name
83
+ self.__send__(:define_singleton_method, method_name, Proc.new do value; end )
84
+ end
85
+
86
+ def values_at *args
87
+ args.map do |key|
88
+ self.respond_to?( key ) ? self.method( key ).call : nil
89
+ end
90
+ end
91
+
92
+ def ignore_equal key = nil
93
+ @ignore_equal||=[]
94
+ @ignore_equal.push key if key
95
+ @ignore_equal
96
+ end
97
+
98
+ def == other
99
+ return false unless other.respond_to? :values_to_compare
100
+ return false unless self.values_to_compare - other.values_to_compare == [] #should not use == cuz arrays can have different orders
101
+ (self.values_to_compare - ignore_equal ).each do |value|
102
+ return false unless self.method(value).() == other.method(value).()
103
+ end
104
+ return true
105
+ end
106
+
107
+
108
+ def method_missing m, *args, &block
109
+ super m, *args, &block if args.length > 0 or block_given?
110
+ nil
111
+ end
112
+
113
+ #retro bunker compatibility
114
+ def [] val
115
+ $stderr.puts 'DEPRECATION WARNING #[] CALLED ON OBJECT'
116
+ raise NameError unless self.respond_to?( val.to_sym )
117
+ self.method( val ).call
118
+ end
119
+
120
+ def to_h
121
+ h = {}
122
+ values_to_compare.each do |m|
123
+ if self.method( m ).().nil? and NULLABLE_KEYS.include?( m )
124
+ next
125
+ end
126
+ if self.method( m ).().respond_to? :values_to_compare
127
+ h[ m.to_sym ] = self.method( m ).().to_h
128
+ elsif self.method( m ).().is_a? Array
129
+ h[ m.to_sym ] = un_objectify_array( self.method( m ).() )
130
+ else
131
+ h[ m.to_sym ] = self.method( m ).()
132
+ end
133
+ end
134
+ return h
135
+ end
136
+
137
+ def empty?
138
+ self.values_to_compare.empty?
139
+ end
140
+
141
+ private
142
+ def un_objectify_array array
143
+ array.map do |v|
144
+ if v.is_a? Array
145
+ un_objectify_array v
146
+ elsif v.respond_to? :values_to_compare
147
+ v.to_h
148
+ else
149
+ v
150
+ end
151
+ end
152
+ end
153
+
154
+
155
+
156
+
157
+ end
158
+
@@ -0,0 +1,6 @@
1
+ # coding: utf-8
2
+ class Hash
3
+ def to_obj
4
+ ObjectifyHash::GenericObject.new( self )
5
+ end
6
+ end
@@ -0,0 +1,4 @@
1
+ # coding: utf-8
2
+ module ObjectifyHash
3
+ VERSION = "2.3.0"
4
+ end
@@ -0,0 +1,308 @@
1
+ # coding: utf-8
2
+ require 'minitest/autorun'
3
+ require 'json'
4
+ require_relative File.join('..','lib','objectifyhash')
5
+ require_relative File.join('..','lib','objectifyhash', 'hash')
6
+
7
+ class A
8
+ include ObjectifyHash
9
+
10
+ ObjectifyHash::EXCEPTIONS.merge!( {duration: Proc.new do 100; end})
11
+
12
+
13
+ end
14
+ class Hash2ObjTest < Minitest::Test
15
+ attr_accessor :a, :hash
16
+
17
+ # Called before every test method runs. Can be used
18
+ # to set up fixture information.
19
+ def setup
20
+ a = '{
21
+ "content": {
22
+ "class": "batatas",
23
+ "assetId": "e473a2f7-dc12-42d3-9933-fd5bd67a32e0",
24
+ "totalLicenses": 10,
25
+ "type": "EST",
26
+ "offerId": "51d4f5d9-ba88-427a-b430-274e9663980c",
27
+ "purchaseDate": "2015-07-07T09:23:17.49Z",
28
+ "ownerId": "6ecb8629-374a-4063-81da-c329f29b405d",
29
+ "ownership": "UserOwnership",
30
+ "canPlay": true,
31
+ "playbackRules": {},
32
+ "canSendToStb": false,
33
+ "canSendSpecs": {},
34
+ "content": {
35
+ "asset": {
36
+ "duration":1
37
+ },
38
+ "resume": {},
39
+ "contents": [
40
+ {
41
+ "asset": {
42
+ "title": "Back to the Future",
43
+ "altTitle": "Back to the Future - Season",
44
+ "slug": "back-to-the-future",
45
+ "shortSynopsis": "A high school student is accidentally sent 30 years into the past in a time-traveling sports car invented by his friend, Dr. Emmett Brown, and must make sure his high-school-age parents unite in order to save his own existence.",
46
+ "duration": 0,
47
+ "number": 1,
48
+ "year": 0,
49
+ "rel": "asset",
50
+ "lastUpdateDate": "2015-03-24T13:52:02Z",
51
+ "assetType": "Season",
52
+ "catalogSection": "Movies",
53
+ "id": "11eb97d3-c8ee-4502-a9dd-410c8b4dd66a",
54
+ "links": [
55
+ {
56
+ "rel": "self",
57
+ "href": "https://qa.skystore.com/api/webP3/v2/catalog/assets/11eb97d3-c8ee-4502-a9dd-410c8b4dd66a/back-to-the-future",
58
+ "needsAuthentication": false
59
+ },
60
+ {
61
+ "rel": "image",
62
+ "href": "http://qa.skystore.com/api/img/asset/en/F80DF38A-D09C-41C9-A419-81C6CF8582F3_3E1EE8E3-D376-4687-8C57-CC57475DE4FE_2015-6-22-T11-11-30.jpg?s={{w}}x{{h}}",
63
+ "needsAuthentication": false
64
+ }
65
+ ]
66
+ },
67
+ "resume": {
68
+ "asset": {
69
+ "title": "Back to the Future",
70
+ "altTitle": "Back to the Future - Movie",
71
+ "slug": "back-to-the-future",
72
+ "shortSynopsis": "A high school student is accidentally sent 30 years into the past in a time-traveling sports car invented by his friend, Dr. Emmett Brown, and must make sure his high-school-age parents unite in order to save his own existence.",
73
+ "duration": 116,
74
+ "year": 1985,
75
+ "rel": "asset",
76
+ "lastUpdateDate": "2015-01-09T11:36:08Z",
77
+ "assetType": "Programme",
78
+ "catalogSection": "Movies",
79
+ "id": "86b39480-87e6-4a99-891a-563fb780871b",
80
+ "links": [
81
+ {
82
+ "rel": "self",
83
+ "href": "https://qa.skystore.com/api/webP3/v2/catalog/assets/86b39480-87e6-4a99-891a-563fb780871b/back-to-the-future",
84
+ "needsAuthentication": false
85
+ },
86
+ {
87
+ "rel": "image",
88
+ "href": "http://qa.skystore.com/api/img/asset/en/F80DF38A-D09C-41C9-A419-81C6CF8582F3_72C3E254-7095-45BB-BF83-3055E08CC204_2015-6-22-T11-12-46.jpg?s={{w}}x{{h}}",
89
+ "needsAuthentication": false
90
+ }
91
+ ]
92
+ },
93
+ "video": {
94
+ "playbackPositionInSeconds": 0,
95
+ "progressPercent": 0,
96
+ "links": [
97
+ {
98
+ "rel": "videoOptions",
99
+ "href": "https://qa.skystore.com/api/webP3/v2/user/entitlements/fa879cad-8753-4040-8702-fd0937eeb7f4/86b39480-87e6-4a99-891a-563fb780871b/video/options",
100
+ "needsAuthentication": true
101
+ }
102
+ ]
103
+ }
104
+ },
105
+ "links": [
106
+ {
107
+ "rel": "self",
108
+ "href": "https://qa.skystore.com/api/webP3/v2/user/entitlements/fa879cad-8753-4040-8702-fd0937eeb7f4/11eb97d3-c8ee-4502-a9dd-410c8b4dd66a",
109
+ "needsAuthentication": true
110
+ }
111
+ ]
112
+ },
113
+ {
114
+ "asset": {
115
+ "title": "Back to the Future FAKE ",
116
+ "altTitle": "Back to the Future - Season",
117
+ "slug": "back-to-the-future",
118
+ "shortSynopsis": "A high school student is accidentally sent 30 years into the past in a time-traveling sports car invented by his friend, Dr. Emmett Brown, and must make sure his high-school-age parents unite in order to save his own existence.",
119
+ "duration": 0,
120
+ "number": 1,
121
+ "year": 0,
122
+ "rel": "asset",
123
+ "lastUpdateDate": "2015-03-24T13:52:02Z",
124
+ "assetType": "Season",
125
+ "catalogSection": "Movies",
126
+ "id": "11eb97d3-c8ee-4502-a9dd-410c8b4dd66a",
127
+ "links": [
128
+ {
129
+ "rel": "self",
130
+ "href": "https://qa.skystore.com/api/webP3/v2/catalog/assets/11eb97d3-c8ee-4502-a9dd-410c8b4dd66a/back-to-the-future",
131
+ "needsAuthentication": false
132
+ },
133
+ {
134
+ "rel": "image",
135
+ "href": "http://qa.skystore.com/api/img/asset/en/F80DF38A-D09C-41C9-A419-81C6CF8582F3_3E1EE8E3-D376-4687-8C57-CC57475DE4FE_2015-6-22-T11-11-30.jpg?s={{w}}x{{h}}",
136
+ "needsAuthentication": false
137
+ }
138
+ ]
139
+ },
140
+ "resume": {
141
+ "asset": {
142
+ "title": "Back to the Future",
143
+ "altTitle": "Back to the Future - Movie",
144
+ "slug": "back-to-the-future",
145
+ "shortSynopsis": "A high school student is accidentally sent 30 years into the past in a time-traveling sports car invented by his friend, Dr. Emmett Brown, and must make sure his high-school-age parents unite in order to save his own existence.",
146
+ "duration": 116,
147
+ "year": 1985,
148
+ "rel": "asset",
149
+ "lastUpdateDate": "2015-01-09T11:36:08Z",
150
+ "assetType": "Programme",
151
+ "catalogSection": "Movies",
152
+ "id": "86b39480-87e6-4a99-891a-563fb780871b",
153
+ "links": [
154
+ {
155
+ "rel": "self",
156
+ "href": "https://qa.skystore.com/api/webP3/v2/catalog/assets/86b39480-87e6-4a99-891a-563fb780871b/back-to-the-future",
157
+ "needsAuthentication": false
158
+ },
159
+ {
160
+ "rel": "image",
161
+ "href": "http://qa.skystore.com/api/img/asset/en/F80DF38A-D09C-41C9-A419-81C6CF8582F3_72C3E254-7095-45BB-BF83-3055E08CC204_2015-6-22-T11-12-46.jpg?s={{w}}x{{h}}",
162
+ "needsAuthentication": false
163
+ }
164
+ ]
165
+ },
166
+ "video": {
167
+ "playbackPositionInSeconds": 0,
168
+ "progressPercent": 0,
169
+ "links": [
170
+ {
171
+ "rel": "videoOptions",
172
+ "href": "https://qa.skystore.com/api/webP3/v2/user/entitlements/fa879cad-8753-4040-8702-fd0937eeb7f4/86b39480-87e6-4a99-891a-563fb780871b/video/options",
173
+ "needsAuthentication": true
174
+ }
175
+ ]
176
+ }
177
+ },
178
+ "links": [
179
+ {
180
+ "rel": "self",
181
+ "href": "https://qa.skystore.com/api/webP3/v2/user/entitlements/fa879cad-8753-4040-8702-fd0937eeb7f4/11eb97d3-c8ee-4502-a9dd-410c8b4dd66a",
182
+ "needsAuthentication": true
183
+ }
184
+ ]
185
+ }
186
+ ]
187
+ },
188
+ "id": "fa879cad-8753-4040-8702-fd0937eeb7f4",
189
+ "links": [
190
+ {
191
+ "rel": "deviceStatus",
192
+ "href": "https://qa.skystore.com/api/webP3/v2/user/devices/status",
193
+ "needsAuthentication": true
194
+ }
195
+ ]
196
+ },
197
+ "meta": {
198
+ "httpCode": 200
199
+ }
200
+ }'
201
+
202
+
203
+
204
+ @hash = JSON.parse a
205
+ @a = A.new
206
+ @a.convert_and_define hash
207
+ end
208
+
209
+
210
+ def test_basic_nesting_key
211
+ assert_equal a.content.assetId, hash['content']['assetId']
212
+ end
213
+
214
+ def test_correct_name_space
215
+ assert_equal a.content.class, A::Content
216
+ end
217
+
218
+ def test_custom_exception
219
+ assert_equal a.content.content.asset.duration, 100
220
+ end
221
+
222
+ def test_arrays_are_arrays
223
+ assert a.content.content.contents.is_a?( Array)
224
+ end
225
+ def test_no_list_namespace
226
+ assert a.content.content.contents.first.is_a?( A::Content::Content::Content) #notice the missing Contents class
227
+ end
228
+
229
+ def test_deep_obj_with_arrays
230
+ assert_equal a.content.content.contents.first.asset.title, hash['content']['content']['contents'].first['asset']['title']
231
+ end
232
+ def test_deep_obj_with_arrays_via_last
233
+ assert_equal a.content.content.contents.last.asset.title, hash['content']['content']['contents'].last['asset']['title']
234
+ end
235
+ def test_camel_case_name
236
+ assert_equal a.content.totalLicenses, hash['content']['totalLicenses']
237
+ end
238
+
239
+
240
+ def test_custom_nullable_keys
241
+ c = a.to_h
242
+ ObjectifyHash::NULLABLE_KEYS.concat [:type]
243
+ b = ObjectifyHash::GenericObject.new c
244
+ assert b.content.content.contents.last.type.nil?
245
+ end
246
+
247
+ def test_to_obj
248
+ assert_equal hash.to_obj.methods(false), a.methods(false)
249
+ end
250
+
251
+ def test_cloned_obj_is_eq
252
+ assert_equal @a, @a.clone #dup won't work because it doesn't copy singleton methods made by objectifyhash
253
+ end
254
+
255
+ def test_object_is_different
256
+ b = ObjectifyHash::GenericObject.new({a: 1, b:2, c: {kunamis: 'frescos'}})
257
+ assert !(@a == b)
258
+ end
259
+
260
+ def test_can_ignore_some_fields
261
+ b = ObjectifyHash::GenericObject.new({a: 1, b:2, c: {kunamis: 'frescos'}})
262
+ c = ObjectifyHash::GenericObject.new({a: 1, b:2, c: {kunamis: 'frescos'}})
263
+
264
+ b.ignore_equal :c
265
+
266
+ assert_equal b,c
267
+ end
268
+
269
+ def test_to_h
270
+ a = {a: 1, b:{c: 2}, d: [1,3,4,[{z:1, y:[1]}]]}
271
+ object = a.to_obj
272
+ assert_equal a, object.to_h
273
+ end
274
+
275
+ def test_nil_if_does_not_have
276
+ assert_nil @a.eyjafjallajökull
277
+ end
278
+
279
+ def test_not_empty
280
+ refute(a.empty?)
281
+ end
282
+
283
+ def test_convert_class_to_klass
284
+ assert_equal 'batatas', a.content.klass
285
+ end
286
+
287
+ def test_is_empty
288
+ ObjectifyHash::NULLABLE_KEYS.clear
289
+ h = ObjectifyHash::GenericObject.new({})
290
+ assert h.empty?
291
+ end
292
+
293
+ def test_allows_top_level_constants
294
+ h = {details: {files: [{name:'file A'}]}, process: '31B'}
295
+ o = ObjectifyHash::GenericObject.new(h)
296
+ assert_equal( {name:'file A'}, o.details.files.first.to_h)
297
+ assert_equal '31B', o.process
298
+ #caviat
299
+ assert o.details.files.first.is_a? ObjectifyHash::GenericObject::File_
300
+ end
301
+
302
+ def test_circuvent_preexisting_methods
303
+ h = {send:{define_singleton_method: 1}}
304
+ o = ObjectifyHash::GenericObject.new(h)
305
+ assert_equal 1, o._send_._define_singleton_method_
306
+ end
307
+
308
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: objectifyhash
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Arthur Silva
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-07-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: json
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.8'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.8'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.8'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5.8'
41
+ description: This gem allows you to easily turn your hashes into objects, great for
42
+ dealing with rest api's
43
+ email:
44
+ - arthur.silva@sky.uk
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - License.txt
50
+ - lib/objectifyhash.rb
51
+ - lib/objectifyhash/hash.rb
52
+ - lib/objectifyhash/version.rb
53
+ - test/hash_to_obj_test.rb
54
+ homepage: https://github.com/sky-uk/skystore-contrib-gem-objectifyhash
55
+ licenses:
56
+ - MIT
57
+ metadata: {}
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ requirements: []
73
+ rubyforge_project:
74
+ rubygems_version: 2.5.1
75
+ signing_key:
76
+ specification_version: 4
77
+ summary: This gem allows you to easily turn your hashes into objects
78
+ test_files: []