json_dumper 0.1.0 → 0.5.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
- SHA1:
3
- metadata.gz: 79357d5f4525bea45352f2a0a4d12e256099254f
4
- data.tar.gz: 3e6a651e6eadd83dbde1c5086580dca624e4cd47
2
+ SHA256:
3
+ metadata.gz: 45c60574d6e74355f5780187c67dffaa8dbec10c66f7daf3333716a314fb2fd9
4
+ data.tar.gz: b38572d61598229c78cea6383aaea4b42fecb1881fc93833c088dcbf74a990af
5
5
  SHA512:
6
- metadata.gz: b67062a0b892a32951eb9b53749b2ffc722829bf6d917ae8ff6944710e42121882f720c99f9820bf6c333a9b6777d7e9ee261994f72f149394f74fdfe0462c2c
7
- data.tar.gz: 52290d5cb95766106bf0fbc290b3d13459dec136dc277a1535060cd5240f98d4fccda6fd671f9060102fb6571f53de500845e9a21af0b0947b509e12a86f77b1
6
+ metadata.gz: 4af873d7fc123e0cf8aa027183a688d2fa555b9f6b709e42504b6da0b1845e3326e5a7e7ce4cedabee4d0f931f8899b11552304154a779d395f4fc11e8e9b7e2
7
+ data.tar.gz: b2352afdd41c7e496188d1503bc3c32b789683ec76ad577bef34cfb2ac1268ebfaad913bfeba0b9df887dd936ae8ef1cd5e0c365fb95b7635867e4810302ec80
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # JsonDumper
2
2
 
3
- Serialize Ruby into JSON.
3
+ Serialize Ruby into JSON. Cleaner. Faster.
4
4
 
5
5
  This gem is intended to
6
6
  * help serialize Ruby objects and ActiveRecord objects into json
@@ -25,7 +25,171 @@ Or install it yourself as:
25
25
 
26
26
  ## Usage
27
27
 
28
- TODO: Write usage instructions here
28
+ Let's say you want to serialize Human object, which has many Cars.
29
+ First define a class that is going to serialize Human:
30
+ ```
31
+ class HumanJson < JsonDumper::Base
32
+ def preview
33
+ {
34
+ id: id,
35
+ first_name: first_name,
36
+ last_name: last_name,
37
+ born_at: created_at.strftime('%m/%d/%Y')
38
+ }
39
+ end
40
+ end
41
+ ```
42
+ you can call it like that:
43
+ ```
44
+ john = Human.create(
45
+ first_name: 'John',
46
+ last_name: 'Doe',
47
+ created_at: 20.years.ago
48
+ )
49
+
50
+ json = HumanJson.preview(john)
51
+ json == {
52
+ id: 1,
53
+ first_name: 'John',
54
+ last_name: 'Doe',
55
+ born_at: '09/19/1997'
56
+ }
57
+ ```
58
+
59
+ Whenever you invoke a method on a JsonDumper::Base instance and it is missing a similar method is invoked on the object you passed to the serializer.
60
+ For example in the snippet above a method `id` is going to be called on `john` object.
61
+ ```
62
+ {
63
+ id: id,
64
+ ...
65
+ }
66
+ ```
67
+
68
+ Let's introduce an association into the mix:
69
+ ```
70
+ class CarJson < JsonDumper::Base
71
+ def preview
72
+ {
73
+ id: id,
74
+ name: name,
75
+ }
76
+ end
77
+ end
78
+
79
+ class HumanJson < JsonDumper::Base
80
+ # ...
81
+ def details
82
+ preview.merge(
83
+ car: CarJson.preview(car)
84
+ )
85
+ end
86
+ end
87
+
88
+ ferrari = Car.create(
89
+ name: 'Ferrari',
90
+ )
91
+ john.car = ferrari
92
+
93
+ json = HumanJson.details(john)
94
+ json == {
95
+ id: 1,
96
+ first_name: 'John',
97
+ last_name: 'Doe',
98
+ born_at: '09/19/1997',
99
+ car: {
100
+ id: 1,
101
+ name: 'Ferrari'
102
+ }
103
+ }
104
+ ```
105
+
106
+ This structure provides a very clean way to specify dependencies for ActiveRecord preloader:
107
+ ```
108
+ class HumanJson < JsonDumper::Base
109
+ def preview
110
+ # ...
111
+ end
112
+
113
+ def preview_preload
114
+ {}
115
+ end
116
+
117
+ def details
118
+ # ...
119
+ end
120
+
121
+ def details_preload
122
+ preview_preload.merge(car: [])
123
+ end
124
+ end
125
+ ```
126
+ Furthermore you can omit defining `preview_preload` because JsonDumper returns empty hashes (`{}`) whenever a method does not exist and its name ends with `_preload`.
127
+
128
+ You can utilize it in the following way:
129
+ ```
130
+ preloader = ActiveRecord::Base::Preloader.new
131
+ preloader.preload(john, HumanJson.details_preload)
132
+ json = HumanJson.details(john)
133
+ ```
134
+ Another cool feature that you can now do is to do both preloading and serialization in a single command via `fetch_METHOD_NAME`.
135
+ This creates a special JsonDumper::Delayed object which delays its execution until it's time to render. This allows to do preloading at render time.
136
+
137
+ Since this is a common operation you can include `JsonDumper::Base` in your controller.
138
+ ```
139
+ class HumansController < ActionController::Base
140
+ include JsonDumper::Helper
141
+
142
+ def show
143
+ human = Human.find(params[:id])
144
+ json = dumper_json(
145
+ my_human: HumanJson.fetch_details(human)
146
+ )
147
+ render json: json
148
+ end
149
+
150
+ # OR
151
+
152
+ def show
153
+ human = Human.find(params[:id])
154
+ render_dumper_json(
155
+ my_human: HumanJson.fetch_details(human)
156
+ )
157
+ end
158
+ end
159
+
160
+ # going to render:
161
+ {
162
+ myHuman: {
163
+ id: 1,
164
+ firstName: 'John',
165
+ lastName: 'Doe',
166
+ bornAt: '09/19/1997',
167
+ car: {
168
+ id: 1,
169
+ name: 'Ferrari'
170
+ }
171
+ }
172
+ }
173
+ ```
174
+ Take a note that `dumper_json` also camelizes your keys.
175
+
176
+ ### Usage with [Gon](https://github.com/gazay/gon)
177
+
178
+ This gem also provides a seamless integration with Gon gem.
179
+ The above example could be rewritten in the following way:
180
+ ```
181
+ class HumansController < ActionController::Base
182
+ def show
183
+ human = Human.find(params[:id])
184
+ gon.my_human = HumanJson.fetch_details(human)
185
+ end
186
+ end
187
+ ```
188
+
189
+ Later in your javascript:
190
+ ```
191
+ console.log(gon.myHuman);
192
+ ```
29
193
 
30
194
  ## Development
31
195
 
@@ -42,3 +206,7 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/therus
42
206
 
43
207
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
44
208
 
209
+ ## Related blogpost
210
+
211
+ Check it out [here](http://www.dmitry-ishkov.com/2017/08/better-ruby-serialization-into-json.html)
212
+
data/lib/json_dumper.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require "json_dumper/version"
2
2
  require "json_dumper/key_transformer"
3
3
  require "json_dumper/dumper_hash"
4
+ require "json_dumper/dumper_array"
4
5
  require "json_dumper/delayed"
5
6
  require "json_dumper/base"
6
7
  require "json_dumper/helper"
@@ -7,12 +7,12 @@ module JsonDumper
7
7
  self.entity = entity
8
8
  end
9
9
 
10
- def self.method_missing(name, *args, &block)
10
+ def self.method_missing(name, *args1, **args2, &block)
11
11
  name_sym = name
12
12
  name = name.to_s
13
- value = args[0]
13
+ value = args1[0]
14
14
  if name.start_with?('fetch_')
15
- return Delayed.new(name.gsub('fetch_', ''), value, args[1..-1], self)
15
+ return Delayed.new(name.gsub('fetch_', ''), value, args1[1..-1], args2, self)
16
16
  end
17
17
  if instance.respond_to?(name)
18
18
  if value.respond_to?(:each) && !value.respond_to?(:each_pair)
@@ -21,7 +21,16 @@ module JsonDumper
21
21
  if new_dumper.return_nils
22
22
  return nil
23
23
  end
24
- result = DumperHash.new(new_dumper.send(name, *(args[1..-1]), &block))
24
+ result = if args2.empty?
25
+ new_dumper.send(name, *(args1[1..-1]), &block)
26
+ else
27
+ new_dumper.send(name, *(args1[1..-1]), **args2, &block)
28
+ end
29
+ if result.respond_to?(:each) && !result.respond_to?(:each_pair)
30
+ result = DumperArray.new(result)
31
+ else
32
+ result = DumperHash.new(result)
33
+ end
25
34
  preload_method_name = "#{name}_preload"
26
35
  result.preload = instance.respond_to?(preload_method_name) ? instance.send(preload_method_name) : {}
27
36
  result
@@ -33,7 +42,17 @@ module JsonDumper
33
42
  if new_dumper.return_nils
34
43
  return nil
35
44
  end
36
- result = DumperHash.new(new_dumper.send(name, *(args[1..-1]), &block))
45
+ result = if args2.empty?
46
+ new_dumper.send(name, *(args1[1..-1]), &block)
47
+ else
48
+ new_dumper.send(name, *(args1[1..-1]), **args2, &block)
49
+ end
50
+ if result.respond_to?(:each) && !result.respond_to?(:each_pair)
51
+ result = DumperArray.new(result)
52
+ else
53
+ result = DumperHash.new(result)
54
+ end
55
+
37
56
  preload_method_name = "#{name}_preload"
38
57
  result.preload = instance.respond_to?(preload_method_name) ? instance.send(preload_method_name) : {}
39
58
  result
@@ -41,7 +60,11 @@ module JsonDumper
41
60
  elsif name.end_with?('_preload') && instance.respond_to?(name.gsub('_preload', ''))
42
61
  return {}
43
62
  else
44
- super name_sym, *args, &block
63
+ if args2.empty?
64
+ super name_sym, *args1, &block
65
+ else
66
+ super name_sym, *args1, *args2, &block
67
+ end
45
68
  end
46
69
  end
47
70
 
@@ -49,11 +72,15 @@ module JsonDumper
49
72
  new.respond_to? method_name
50
73
  end
51
74
 
52
- def method_missing(name, *args, &block)
75
+ def method_missing(name, *args1, **args2, &block)
53
76
  if entity.respond_to? name
54
- entity.send(name, *args, &block)
77
+ if args2.empty?
78
+ entity.send(name, *args1, &block)
79
+ else
80
+ entity.send(name, *args1, **args2, &block)
81
+ end
55
82
  else
56
- super name, *args, &block
83
+ super
57
84
  end
58
85
  end
59
86
 
@@ -1,12 +1,13 @@
1
1
  module JsonDumper
2
2
  class Delayed
3
- attr_accessor :method_name, :entity, :args, :klass
3
+ attr_accessor :method_name, :entity, :positional_args, :named_args, :klass
4
4
 
5
- def initialize(method_name, entity, args, klass)
5
+ def initialize(method_name, entity, positional_args, named_args, klass)
6
6
  self.method_name = method_name
7
7
  self.entity = entity
8
- self.args = args
8
+ self.positional_args = positional_args
9
+ self.named_args = named_args
9
10
  self.klass = klass
10
11
  end
11
12
  end
12
- end
13
+ end
@@ -0,0 +1,9 @@
1
+ module JsonDumper
2
+ class DumperArray < Array
3
+ attr_accessor :preload
4
+
5
+ def camel
6
+ JsonDumper::KeyTransformer.keys_to_camelcase_array(self)
7
+ end
8
+ end
9
+ end
@@ -18,7 +18,11 @@ module JsonDumper
18
18
  def dumper_fetch(delayed, camelcase: true)
19
19
  preload_hash = delayed.klass.send("#{delayed.method_name}_preload")
20
20
  preloader.preload(delayed.entity,preload_hash)
21
- result = delayed.klass.send(delayed.method_name, delayed.entity, *delayed.args)
21
+ result = if delayed.named_args.empty?
22
+ delayed.klass.send(delayed.method_name, delayed.entity, *delayed.positional_args)
23
+ else
24
+ delayed.klass.send(delayed.method_name, delayed.entity, *delayed.positional_args, **delayed.named_args)
25
+ end
22
26
  if camelcase
23
27
  result = KeyTransformer.keys_to_camelcase(result)
24
28
  end
@@ -32,4 +36,4 @@ module JsonDumper
32
36
  ActiveRecord::Base::Preloader.new
33
37
  end
34
38
  end
35
- end
39
+ end
@@ -1,6 +1,7 @@
1
1
  module JsonDumper
2
2
  class KeyTransformer
3
3
  def self.keys_to_camelcase(obj)
4
+ return nil if obj.nil?
4
5
  if array_like?(obj)
5
6
  return keys_to_camelcase_array(obj)
6
7
  end
@@ -5,6 +5,8 @@ if defined?(Gon)
5
5
  def set_variable(name, value)
6
6
  if value.is_a?(::JsonDumper::Delayed)
7
7
  value = Class.new.extend(::JsonDumper::Helper).dumper_fetch(value)
8
+ elsif value.respond_to?(:each)
9
+ value = ::JsonDumper::KeyTransformer.keys_to_camelcase(value)
8
10
  end
9
11
  current_gon.gon[::JsonDumper::KeyTransformer.camelize(name)] = value
10
12
  end
@@ -1,3 +1,3 @@
1
1
  module JsonDumper
2
- VERSION = "0.1.0"
2
+ VERSION = "0.5.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json_dumper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - therusskiy
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-08-13 00:00:00.000000000 Z
11
+ date: 2021-03-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -80,7 +80,7 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
- description:
83
+ description:
84
84
  email:
85
85
  - dimanrussian@gmail.com
86
86
  executables: []
@@ -101,6 +101,7 @@ files:
101
101
  - lib/json_dumper.rb
102
102
  - lib/json_dumper/base.rb
103
103
  - lib/json_dumper/delayed.rb
104
+ - lib/json_dumper/dumper_array.rb
104
105
  - lib/json_dumper/dumper_hash.rb
105
106
  - lib/json_dumper/helper.rb
106
107
  - lib/json_dumper/key_transformer.rb
@@ -110,7 +111,7 @@ homepage: https://www.github.com/therusskiy/json_dumper
110
111
  licenses:
111
112
  - MIT
112
113
  metadata: {}
113
- post_install_message:
114
+ post_install_message:
114
115
  rdoc_options: []
115
116
  require_paths:
116
117
  - lib
@@ -125,9 +126,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
125
126
  - !ruby/object:Gem::Version
126
127
  version: '0'
127
128
  requirements: []
128
- rubyforge_project:
129
- rubygems_version: 2.6.10
130
- signing_key:
129
+ rubygems_version: 3.1.2
130
+ signing_key:
131
131
  specification_version: 4
132
132
  summary: Serialize ruby objects for javascript consumption
133
133
  test_files: []