jsoning 0.3.0 → 0.4.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 +4 -4
- data/README.md +57 -3
- data/lib/jsoning/dsl/for_dsl.rb +1 -1
- data/lib/jsoning/foundations/mapper.rb +26 -14
- data/lib/jsoning/foundations/protocol.rb +30 -2
- data/lib/jsoning/version.rb +1 -1
- data/lib/jsoning.rb +19 -12
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b62e31437ea7ae41f6aabc42ce7096cba6475eca
|
4
|
+
data.tar.gz: fdb1858c496487d96805d98a00640af0bb8e97d8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65ebaacd3211f4a650965b474bd90fc8b6a72117080fb30966a5a9015f98ffe1917b63108647e2cc3df26fef554b68b689a93713d462d714460dc48fe787a9e6
|
7
|
+
data.tar.gz: 7d6c24558e6fc76fbe06b52df2f91288563b83379edc68cae955a45f24f784169a7842b05128a9a8110a1601482f871c3ca7089c3d596fbd9dbdba9496f6672e
|
data/README.md
CHANGED
@@ -169,9 +169,7 @@ Jsoning the user with pretty set to true, will return:
|
|
169
169
|
}
|
170
170
|
```
|
171
171
|
|
172
|
-
|
173
|
-
|
174
|
-
It is also possible to return hash as well:
|
172
|
+
It is also possible to retrieve in form of Ruby hash rather than JSON string:
|
175
173
|
|
176
174
|
```ruby
|
177
175
|
Jsoning[user]
|
@@ -199,6 +197,57 @@ Jsoning.add_type MyFancyString, processor: { |fancy_string| fancy_string.get_str
|
|
199
197
|
Internally, it is how Jsoning convert date-like data type (`Date`, `DateTime`, `Time`, `ActiveSupport::TimeWithZone`) to
|
200
198
|
ISO8601 which can be parsed by compliant JavaScript interpreter in the browser (or somewhere else).
|
201
199
|
|
200
|
+
## Parsing JSON back to Hash
|
201
|
+
|
202
|
+
The `JSON` library that is part of Ruby Standard Library already support parsing from JSON string to Hash.
|
203
|
+
However, if you feel that you need to assign default value, for example, when a value is missing, or when you want to
|
204
|
+
enforce the schema, Ruby's own `JSON` library cannot do that yet. Jsoning, on the other hand, can.
|
205
|
+
|
206
|
+
The schema must have been defined by using `Jsoning.for` as have been demonstrated earlier.
|
207
|
+
|
208
|
+
Until then, to convert from JSON string to Hash, one can call:
|
209
|
+
|
210
|
+
```ruby
|
211
|
+
Jsoning.parse(the_json_string, Class)
|
212
|
+
```
|
213
|
+
|
214
|
+
For example, given:
|
215
|
+
|
216
|
+
```ruby
|
217
|
+
Jsoning.for(My::User) do
|
218
|
+
key :name, null: false
|
219
|
+
key :years_old, from: :age
|
220
|
+
key :gender, default: "male"
|
221
|
+
key :books, default: proc {
|
222
|
+
default_college_books = []
|
223
|
+
default_college_books << My::Book.new("Mathematics 6A")
|
224
|
+
default_college_books << My::Book.new("Physics A2")
|
225
|
+
default_college_books
|
226
|
+
}
|
227
|
+
key :degree_detail, from: :taken_degree
|
228
|
+
end
|
229
|
+
|
230
|
+
the_json_string = %Q{
|
231
|
+
{"name":"Adam Baihaqi",
|
232
|
+
"years_old":21,
|
233
|
+
"gender":"male",
|
234
|
+
"books":[{"name":"Mathematics 6A"},{"name":"Physics A2"}],
|
235
|
+
"degree_detail":null,
|
236
|
+
"registered_at":"2015-11-01T14:41:09+00:00"}
|
237
|
+
}
|
238
|
+
```
|
239
|
+
|
240
|
+
Calling: `Jsoning.parse(the_json_string, My::User)` will yield a Hash as follow:
|
241
|
+
|
242
|
+
```ruby
|
243
|
+
{"name"=>"Adam Baihaqi",
|
244
|
+
"years_old"=>21,
|
245
|
+
"gender"=>"male",
|
246
|
+
"books"=>[{"name"=>"Mathematics 6A"}, {"name"=>"Physics A2"}],
|
247
|
+
"degree_detail"=>nil,
|
248
|
+
"registered_at"=>"2015-11-01T14:41:09+00:00"}
|
249
|
+
```
|
250
|
+
|
202
251
|
## Changelog
|
203
252
|
|
204
253
|
== Version 0.1.0
|
@@ -214,6 +263,11 @@ ISO8601 which can be parsed by compliant JavaScript interpreter in the browser (
|
|
214
263
|
1. Allow user to specify how Jsoning would extract value from a custom data type
|
215
264
|
2. Date, DateTime, Time, ActiveSupport::TimeWithZone now is by default parsed to ISO8601 format.
|
216
265
|
|
266
|
+
== Version 0.4.0
|
267
|
+
|
268
|
+
1. When passing a proc as default value, it will be executed to assign default value when value is nil.
|
269
|
+
2. Parsing JSON string as hash by using `Jsoning.parse`
|
270
|
+
|
217
271
|
## License
|
218
272
|
|
219
273
|
The gem is proudly available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/lib/jsoning/dsl/for_dsl.rb
CHANGED
@@ -34,7 +34,7 @@ class Jsoning::ForDsl
|
|
34
34
|
mapper.name = mapped_to
|
35
35
|
mapper.default_value = options.delete(:default) || options.delete("default")
|
36
36
|
mapper.nullable = options.delete(:null)
|
37
|
-
mapper.nullable = options.delete("null") if mapper.nullable
|
37
|
+
mapper.nullable = options.delete("null") if mapper.nullable?.nil?
|
38
38
|
|
39
39
|
options.keys { |key| raise Jsoning::Error, "Undefined option: #{key}" }
|
40
40
|
|
@@ -1,9 +1,9 @@
|
|
1
|
-
#
|
1
|
+
# responsible of mapping from object to representable values, one field at a time
|
2
2
|
class Jsoning::Mapper
|
3
3
|
# when mapped, what will be the mapped name
|
4
4
|
attr_writer :name
|
5
5
|
|
6
|
-
|
6
|
+
attr_writer :default_value
|
7
7
|
attr_writer :nullable
|
8
8
|
# what variable in the object will be used to obtain the value
|
9
9
|
attr_accessor :parallel_variable
|
@@ -11,11 +11,11 @@ class Jsoning::Mapper
|
|
11
11
|
|
12
12
|
def initialize
|
13
13
|
self.parallel_variable = nil
|
14
|
-
|
14
|
+
@default_value = nil
|
15
15
|
self.nullable = true
|
16
16
|
end
|
17
17
|
|
18
|
-
def nullable
|
18
|
+
def nullable?
|
19
19
|
if @nullable.is_a?(TrueClass) || @nullable.is_a?(FalseClass)
|
20
20
|
return @nullable
|
21
21
|
else
|
@@ -31,18 +31,31 @@ class Jsoning::Mapper
|
|
31
31
|
|
32
32
|
# map this very specific object's field to target_hash
|
33
33
|
def extract(object, target_hash)
|
34
|
+
target_value = nil
|
35
|
+
|
34
36
|
if object.respond_to?(parallel_variable)
|
35
37
|
parallel_val = object.send(parallel_variable)
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
target_value = deep_parse(parallel_val)
|
39
|
+
end
|
40
|
+
|
41
|
+
if target_value.nil?
|
42
|
+
target_value = self.default_value
|
43
|
+
if target_value.nil? && !self.nullable?
|
44
|
+
raise Jsoning::Error, "Null value given for '#{name}' when serializing #{object}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
target_hash[name] = deep_parse(target_value)
|
48
|
+
end
|
49
|
+
|
50
|
+
def default_value
|
51
|
+
if @default_value
|
52
|
+
if @default_value.is_a?(Proc)
|
53
|
+
return deep_parse(@default_value.())
|
41
54
|
else
|
42
|
-
|
43
|
-
raise Jsoning::Error, "Null value given for '#{name}' when serializing #{object}"
|
44
|
-
end
|
55
|
+
return deep_parse(@default_value)
|
45
56
|
end
|
57
|
+
else
|
58
|
+
nil
|
46
59
|
end
|
47
60
|
end
|
48
61
|
|
@@ -69,11 +82,10 @@ class Jsoning::Mapper
|
|
69
82
|
parsed_data = object
|
70
83
|
else
|
71
84
|
protocol = Jsoning.protocol_for!(object.class)
|
72
|
-
parsed_data = protocol.
|
85
|
+
parsed_data = protocol.retrieve_values_from(object)
|
73
86
|
end
|
74
87
|
end
|
75
88
|
|
76
|
-
|
77
89
|
parsed_data
|
78
90
|
end
|
79
91
|
end
|
@@ -31,7 +31,7 @@ class Jsoning::Protocol
|
|
31
31
|
pretty = options["pretty"] if pretty.nil?
|
32
32
|
pretty = false if pretty.nil?
|
33
33
|
|
34
|
-
data =
|
34
|
+
data = retrieve_values_from(object)
|
35
35
|
|
36
36
|
if pretty
|
37
37
|
JSON.pretty_generate(data)
|
@@ -40,7 +40,8 @@ class Jsoning::Protocol
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
|
43
|
+
# construct the JSON from given object
|
44
|
+
def retrieve_values_from(object)
|
44
45
|
# hold data here
|
45
46
|
data = {}
|
46
47
|
|
@@ -52,6 +53,33 @@ class Jsoning::Protocol
|
|
52
53
|
data
|
53
54
|
end
|
54
55
|
|
56
|
+
# construct hash from given JSON
|
57
|
+
def construct_hash_from(json_string)
|
58
|
+
data = {}
|
59
|
+
|
60
|
+
# make all json obj keys to downcase, symbol
|
61
|
+
json_obj = JSON.parse(json_string)
|
62
|
+
json_obj = Hash[json_obj.map { |k, v| [k.to_s.downcase, v]}]
|
63
|
+
|
64
|
+
mappers_order.each do |mapper_sym|
|
65
|
+
mapper = mapper_for(mapper_sym)
|
66
|
+
mapper_key_name = mapper.name.to_s.downcase
|
67
|
+
|
68
|
+
mapper_default_value = mapper.default_value
|
69
|
+
mapper_key_value = json_obj[mapper_key_name]
|
70
|
+
# retrieve value from key, if not available, from default
|
71
|
+
value = mapper_key_value || mapper_default_value
|
72
|
+
|
73
|
+
if value.nil? && !mapper.nullable?
|
74
|
+
raise Jsoning::Error, "Constructing hash failed due to #{mapper_key_name} being nil when it is not allowed to"
|
75
|
+
end
|
76
|
+
|
77
|
+
data[mapper_key_name] = value
|
78
|
+
end
|
79
|
+
|
80
|
+
data
|
81
|
+
end
|
82
|
+
|
55
83
|
private
|
56
84
|
def canonical_name(key_name)
|
57
85
|
key_name.to_s.downcase.to_sym
|
data/lib/jsoning/version.rb
CHANGED
data/lib/jsoning.rb
CHANGED
@@ -24,20 +24,24 @@ module Jsoning
|
|
24
24
|
protocol
|
25
25
|
end
|
26
26
|
|
27
|
+
# retrieve the protocol or raise an error when the protocol is not defined yet
|
27
28
|
def protocol_for!(klass)
|
28
29
|
protocol = PROTOCOLS[klass.to_s]
|
29
30
|
raise Jsoning::Error, "Undefined Jsoning protocol for #{klass.to_s}" if protocol.nil?
|
30
31
|
protocol
|
31
32
|
end
|
32
33
|
|
34
|
+
# clearing the protocols
|
33
35
|
def clear
|
34
36
|
PROTOCOLS.clear
|
35
37
|
end
|
36
38
|
|
39
|
+
# define the protocol
|
37
40
|
def for(klass, &block)
|
38
41
|
Jsoning::ForDsl.new(protocol_for(klass)).instance_eval(&block)
|
39
42
|
end
|
40
43
|
|
44
|
+
# generate the json document
|
41
45
|
def generate(object, options = {})
|
42
46
|
initialize_type_extensions
|
43
47
|
protocol = protocol_for!(object.class)
|
@@ -80,19 +84,16 @@ module Jsoning
|
|
80
84
|
end
|
81
85
|
end
|
82
86
|
|
83
|
-
|
84
|
-
def add_type(klass, options = {})
|
85
|
-
processor = options[:processor]
|
86
|
-
raise Jsoning::Error, "Pass in processor that is a proc explaining how to extract the value" unless processor.is_a?(Proc)
|
87
|
-
|
88
|
-
TYPE_EXTENSIONS[klass.to_s] = processor
|
89
|
-
nil
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
def self.[](object)
|
87
|
+
def [](object)
|
94
88
|
protocol = protocol_for!(object.class)
|
95
|
-
protocol.
|
89
|
+
protocol.retrieve_values_from(object)
|
90
|
+
end
|
91
|
+
|
92
|
+
def add_type(klass, options = {})
|
93
|
+
processor = options[:processor]
|
94
|
+
raise Jsoning::Error, "Pass in processor that is a proc explaining how to extract the value" unless processor.is_a?(Proc)
|
95
|
+
TYPE_EXTENSIONS[klass.to_s] = processor
|
96
|
+
nil
|
96
97
|
end
|
97
98
|
|
98
99
|
# monkey patch Kernel
|
@@ -103,4 +104,10 @@ module Jsoning
|
|
103
104
|
Jsoning.generate(object, options)
|
104
105
|
end
|
105
106
|
end
|
107
|
+
|
108
|
+
# parse the JSON String to Hash
|
109
|
+
def parse(json_string, klass)
|
110
|
+
protocol = protocol_for!(klass)
|
111
|
+
protocol.construct_hash_from(json_string)
|
112
|
+
end
|
106
113
|
end
|