jsonite 0.0.2 → 0.0.3

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: 001f4ee4203a2a9ad449b3ce2be7bef23ba649dc
4
- data.tar.gz: cf3d345ce6b1e7194edf8a009512b5a5873f3972
3
+ metadata.gz: 5612be53563ec019fa0b12169f778105d529896c
4
+ data.tar.gz: f19a895e932ae5b559f5de7699c39df930189713
5
5
  SHA512:
6
- metadata.gz: c819dffe0197681f90b17d6e86b5e219861538830c966d2b6f23e3497018c70e09d3070147a618684bb661ed8a42ee95d3c41f01d7e5a9c7bb8854ece3176746
7
- data.tar.gz: 73ce6f0f49069b446b458347a3803d162b4bdd21d6ffd8ce74323d8e5e8a1f52b27a1a6d8b3c2a2e6d97c8496932d762dba5993bc332acf1fa1fc6b47e358b79
6
+ metadata.gz: 3273041c6a95535e89442a3d99ddf8bf6e2fe8dc3ce94d1a8e2c109a50f4b915a98ffc0ecefcfd42e3f026d7524993f9b3e9c1421b76bf0c8dc4c55e0af9c462
7
+ data.tar.gz: 461ea18c18c82ee91734e644cebfea19a733b2951a072ce39b4ca0244f7a1a3c2a9d1eca3657e7afb45a289ff1e7aa9c0accf6ddffe47ae0463b5065a0841db5
data/lib/jsonite.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'active_support/core_ext/object/blank'
2
2
  require 'active_support/json/encoding'
3
3
  require 'jsonite/helper'
4
+ require 'jsonite/lets_proxy'
4
5
 
5
6
  # = Jsonite
6
7
  #
@@ -23,29 +24,25 @@ class Jsonite
23
24
  # # => [{"email"=>"stephen@example.com"}, ...]
24
25
  #
25
26
  # Configuration options:
27
+ # * <tt>:root</tt> - A root key to wrap the resource with.
26
28
  # * <tt>:with</tt> - A specified presenter (defaults to `self`).
27
29
  #
28
- # All other options are passed along to <tt>#as_json</tt>.
30
+ # All other options are passed along to <tt>#present</tt>.
29
31
  def present resource, options = {}
30
32
  presenter = options.delete(:with) { self }
31
33
 
32
- case resource
33
- when Jsonite
34
- resource.as_json options
35
- else
36
- resource = if resource.respond_to?(:to_ary)
37
- resource.to_ary.map do |r|
38
- present presenter.new(r), options.merge(root: nil)
39
- end
40
- elsif resource.respond_to?(:as_json)
41
- present presenter.new(resource), options.merge(root: nil)
42
- else
43
- resource
34
+ presented = if resource.is_a? Jsonite
35
+ resource.present options
36
+ elsif resource.respond_to?(:to_ary)
37
+ resource.to_ary.map do |member|
38
+ presenter.new(member).present options.merge root: nil
44
39
  end
45
-
46
- root = options.fetch :root, Helper.resource_name(resource)
47
- root ? { root => resource } : resource
40
+ else
41
+ presenter.new(resource).present options.merge root: nil
48
42
  end
43
+
44
+ root = options.fetch(:root) { Helper.resource_name(resource) }
45
+ root ? { root => presented } : presented
49
46
  end
50
47
 
51
48
  # Defines a property to be exposed during presentation.
@@ -61,14 +58,9 @@ class Jsonite
61
58
  # * <tt>:with</tt> - A specified presenter. Ignored when a handler is
62
59
  # present. Useful when you want to embed a resource as a property (rather
63
60
  # than in the <tt>_embedded</tt> node).
61
+ # * <tt>:ignore_nil</tt> - Ignore `nil`.
64
62
  def property name, options = {}, &handler
65
- handler ||= if options[:with]
66
- proc { Jsonite.present send(name), with: options[:with] }
67
- else
68
- proc { send name }
69
- end
70
-
71
- properties[name] = handler
63
+ properties[name.to_s] = { handler: handler }.merge options
72
64
  end
73
65
 
74
66
  def properties *properties
@@ -102,7 +94,7 @@ class Jsonite
102
94
  #
103
95
  # class UserPresenter < Jsonite
104
96
  # link :todos, title: 'To-dos', templated: true do |context|
105
- # "#{context.user_todos_url self}{?done}
97
+ # "#{context.user_todos_url self}{?done}"
106
98
  # end
107
99
  # end
108
100
  # # {
@@ -115,7 +107,7 @@ class Jsonite
115
107
  # # }
116
108
  # # }
117
109
  def link rel = :self, options = {}, &handler
118
- links[rel] = options.merge handler: Proc.new # enforce handler presence
110
+ links[rel.to_s] = { handler: Proc.new }.merge options # require handler
119
111
  end
120
112
 
121
113
  def links
@@ -143,27 +135,40 @@ class Jsonite
143
135
  # Configuration options:
144
136
  # * <tt>:with</tt> - A specified presenter. Required if a handler isn't
145
137
  # present.
138
+ # * <tt>:ignore_nil</tt> - Ignore `nil`.
146
139
  def embed rel, options = {}, &handler
147
- if handler.nil?
148
- presenter = options.fetch :with
149
- handler = proc do |context|
150
- Jsonite.present send(rel), with: presenter, context: context
151
- end
152
- end
153
-
154
- embedded[rel] = handler
140
+ options.fetch :with unless handler
141
+ embedded[rel.to_s] = { handler: handler }.merge options
155
142
  end
156
143
 
157
144
  def embedded
158
145
  @embedded ||= {}
159
146
  end
160
147
 
148
+ # Defines a memoized "virtual" method on the resource.
149
+ #
150
+ # class UserPresenter < Jsonite
151
+ # let(:full_name) { "#{first_name} #{last_name}" }
152
+ # property :full_name
153
+ # end
154
+ # # {
155
+ # # "full_name": "Stephen Celis"
156
+ # # }
157
+ def let name, &handler
158
+ lets[name.to_s] = handler
159
+ end
160
+
161
+ def lets
162
+ @lets ||= {}
163
+ end
164
+
161
165
  private
162
166
 
163
167
  def inherited presenter
164
168
  presenter.properties.update properties
165
169
  presenter.links.update links
166
170
  presenter.embedded.update embedded
171
+ presenter.lets.update lets
167
172
  end
168
173
 
169
174
  end
@@ -177,49 +182,72 @@ class Jsonite
177
182
  @resource, @defaults = resource, defaults
178
183
  end
179
184
 
180
- # Returns a JSON representation (Hash) of the resource.
185
+ # Returns a raw representation (Hash) of the resource.
181
186
  #
182
187
  # Options:
183
188
  # * <tt>:context</tt> - A context to pass a presenter instance while
184
189
  # rendering properties, links, and embedded resources.
185
- def as_json options = {}
186
- return resource.as_json options if instance_of? Jsonite
190
+ def present options = {}
187
191
  options = defaults.merge options
192
+
188
193
  context = options.delete :context
189
- hash = properties context
190
- hash.update _links: links(context) if self.class.links.present?
191
- hash.update _embedded: embedded(context) if self.class.embedded.present?
192
- hash.as_json options
194
+ proxied = LetsProxy.new resource, context, self.class.lets
195
+
196
+ presented = properties proxied, context
197
+ _links = links proxied, context
198
+ presented['_links'] = _links if _links.present?
199
+ _embedded = embedded proxied, context
200
+ presented['_embedded'] = _embedded if _embedded.present?
201
+
202
+ root = options.fetch(:root) { Helper.resource_name(resource) }
203
+ root ? { root => presented } : presented
204
+ end
205
+
206
+ # Returns a JSON-ready representation (Hash) of the resource.
207
+ #
208
+ # Options:
209
+ # * <tt>:root</tt>
210
+ def as_json options = {}
211
+ present(options).as_json options
193
212
  end
194
213
 
195
214
  private
196
215
 
197
- def properties context = nil
198
- context ||= resource
199
- self.class.properties.each_with_object({}) do |(name, handler), props|
200
- catch :ignore do
201
- props[name] = resource.instance_exec context, &handler
202
- end
216
+ def properties rsrc, context = nil
217
+ self.class.properties.each_with_object({}) do |(name, options), props|
218
+ catch(:ignore) { props[name] = fetch name, rsrc, context, options }
203
219
  end
204
220
  end
205
221
 
206
- def links context = nil
207
- context ||= resource
222
+ def links rsrc, context = nil
208
223
  self.class.links.each_with_object({}) do |(rel, link), links|
209
224
  catch :ignore do
210
- href = resource.instance_exec context, &link[:handler]
211
- links[rel] = { href: href }.merge link.except :handler
225
+ href = fetch rel, rsrc, context, link
226
+ links[rel] = { 'href' => href }.merge link.except :handler
212
227
  end
213
228
  end
214
229
  end
215
230
 
216
- def embedded context = nil
217
- context ||= resource
218
- self.class.embedded.each_with_object({}) do |(name, handler), embedded|
219
- catch :ignore do
220
- embedded[name] = resource.instance_exec context, &handler
221
- end
231
+ def embedded rsrc, context = nil
232
+ self.class.embedded.each_with_object({}) do |(name, options), embeds|
233
+ catch(:ignore) { embeds[name] = fetch name, rsrc, context, options }
234
+ end
235
+ end
236
+
237
+ def fetch name, rsrc, context, options
238
+ value = if options[:handler]
239
+ rsrc.instance_exec context, &options[:handler]
240
+ else
241
+ rsrc.__send__ name
222
242
  end
243
+
244
+ throw :ignore if options[:ignore_nil] && value.nil?
245
+
246
+ if options[:with] && !value.nil?
247
+ return options[:with].present value, context: context, root: nil
248
+ end
249
+
250
+ value
223
251
  end
224
252
 
225
253
  end
@@ -6,7 +6,7 @@ class Jsonite
6
6
  module_function
7
7
 
8
8
  def resource_name resource
9
- if resource.respond_to? :model_name
9
+ if resource.respond_to?(:model_name) && resource.respond_to?(:to_ary)
10
10
  resource.model_name.collection
11
11
  elsif resource.class.respond_to? :model_name
12
12
  resource.class.model_name.singular
@@ -0,0 +1,23 @@
1
+ class Jsonite
2
+ class LetsProxy < BasicObject
3
+
4
+ undef_method :==, :!, :!=
5
+
6
+ def initialize object, context, lets = {}
7
+ @__object__, @__context__, @__lets__ = object, context, lets
8
+
9
+ @__memoized__ = ::Hash.new do |memoized, name|
10
+ memoized[name] = instance_exec @__context__, &@__lets__.fetch(name)
11
+ end
12
+ end
13
+
14
+ def method_missing name, *args, &block
15
+ if @__lets__.key?(name.to_s)
16
+ @__memoized__[name.to_s]
17
+ else
18
+ @__object__.__send__ name, *args, &block
19
+ end
20
+ end
21
+
22
+ end
23
+ end
@@ -1,5 +1,5 @@
1
1
  class Jsonite
2
2
 
3
- VERSION = '0.0.2'
3
+ VERSION = '0.0.3'
4
4
 
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Celis
@@ -9,20 +9,34 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-08-02 00:00:00.000000000 Z
12
+ date: 2015-05-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - '>='
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
20
  version: 3.1.0
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - '>='
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: 3.1.0
28
+ - !ruby/object:Gem::Dependency
29
+ name: activemodel
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: 3.1.0
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
26
40
  - !ruby/object:Gem::Version
27
41
  version: 3.1.0
28
42
  - !ruby/object:Gem::Dependency
@@ -61,9 +75,10 @@ executables: []
61
75
  extensions: []
62
76
  extra_rdoc_files: []
63
77
  files:
78
+ - lib/jsonite.rb
64
79
  - lib/jsonite/helper.rb
80
+ - lib/jsonite/lets_proxy.rb
65
81
  - lib/jsonite/version.rb
66
- - lib/jsonite.rb
67
82
  homepage: https://github.com/barrelage/jsonite
68
83
  licenses:
69
84
  - MIT
@@ -74,18 +89,19 @@ require_paths:
74
89
  - lib
75
90
  required_ruby_version: !ruby/object:Gem::Requirement
76
91
  requirements:
77
- - - '>='
92
+ - - ">="
78
93
  - !ruby/object:Gem::Version
79
94
  version: 1.9.3
80
95
  required_rubygems_version: !ruby/object:Gem::Requirement
81
96
  requirements:
82
- - - '>='
97
+ - - ">="
83
98
  - !ruby/object:Gem::Version
84
99
  version: '0'
85
100
  requirements: []
86
101
  rubyforge_project:
87
- rubygems_version: 2.0.2
102
+ rubygems_version: 2.2.2
88
103
  signing_key:
89
104
  specification_version: 4
90
105
  summary: A tiny, HAL-compliant JSON presenter
91
106
  test_files: []
107
+ has_rdoc: false