jsoning 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2edd1def968d6f13f1ba2cc36243718163cd7dcc
4
- data.tar.gz: 2e18b982c6b0269727b827d782ea72695f904d7f
3
+ metadata.gz: b62e31437ea7ae41f6aabc42ce7096cba6475eca
4
+ data.tar.gz: fdb1858c496487d96805d98a00640af0bb8e97d8
5
5
  SHA512:
6
- metadata.gz: c2799fd887a3db49f97de68228f5fc4a5634f7b91466a0f119b56b7c3565e10bbb4856d5896c0422bddc5767fcd32284031873ef7dae1d97c5d68faef45b57ab
7
- data.tar.gz: 5622840a2c4ddf1efa7141fa17c01793aff7bde1468113e407d676a099e08616a14a17b8f0b1f5721aaf60d219e7a283de7716582da50e374d74c6cf0f1d69e3
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
- ## Returning Hash
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).
@@ -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.nil?
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
- # takes care of translating/fetching values from the object
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
- attr_accessor :default_value
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
- self.default_value = nil
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
- parallel_val = default_value if parallel_val.nil?
37
- target_hash[name] = deep_parse(parallel_val)
38
- else
39
- if default_value
40
- target_hash[name] = deep_parse(default_value)
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
- unless nullable
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.parse(object)
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 = parse(object)
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
- def parse(object)
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
@@ -1,3 +1,3 @@
1
1
  module Jsoning
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
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
- class << self
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.parse(object)
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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsoning
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Pahlevi