json_dumper 0.1.0 → 0.5.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
- 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: []