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 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