Class: Jsonite

Inherits:
Object
  • Object
show all
Defined in:
lib/jsonite.rb,
lib/jsonite/helper.rb,
lib/jsonite/version.rb,
lib/jsonite/lets_proxy.rb

Overview

Jsonite

A tiny, HAL-compliant JSON presenter.

tools.ietf.org/html/draft-kelly-json-hal-05

Defined Under Namespace

Modules: Helper Classes: LetsProxy

Constant Summary collapse

VERSION =
'0.0.3'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(resource, defaults = {}) ⇒ Jsonite

Initializes a new presenter instance with the given resource.

Default options are passed to #as_json during presentation.



181
182
183
# File 'lib/jsonite.rb', line 181

def initialize resource, defaults = {}
  @resource, @defaults = resource, defaults
end

Instance Attribute Details

#defaultsObject (readonly)

Returns the value of attribute defaults.



176
177
178
# File 'lib/jsonite.rb', line 176

def defaults
  @defaults
end

#resourceObject (readonly)

Returns the value of attribute resource.



176
177
178
# File 'lib/jsonite.rb', line 176

def resource
  @resource
end

Class Method Details

.embed(rel, options = {}, &handler) ⇒ Object

Defines an embedded resource.

class TodoPresenter < Jsonite
  property :description
end
class UserPresenter < Jsonite
  embed :todos, with: TodoPresenter
end
# {
#   "_embedded": {
#     "todos": [
#       {
#         "description": "Buy milk"
#       }
#     ]
#   }
# }

Configuration options:

  • :with - A specified presenter. Required if a handler isn’t present.

  • :ignore_nil - Ignore ‘nil`.



139
140
141
142
# File 'lib/jsonite.rb', line 139

def embed rel, options = {}, &handler
  options.fetch :with unless handler
  embedded[rel.to_s] = { handler: handler }.merge options
end

.embeddedObject



144
145
146
# File 'lib/jsonite.rb', line 144

def embedded
  @embedded ||= {}
end

.let(name, &handler) ⇒ Object

Defines a memoized “virtual” method on the resource.

class UserPresenter < Jsonite
  let(:full_name) { "#{first_name} #{last_name}" }
  property :full_name
end
# {
#   "full_name": "Stephen Celis"
# }


157
158
159
# File 'lib/jsonite.rb', line 157

def let name, &handler
  lets[name.to_s] = handler
end

.letsObject



161
162
163
# File 'lib/jsonite.rb', line 161

def lets
  @lets ||= {}
end

Defines a link.

class UserPresenter < Jsonite
  link do |context|
    context.user_url self
  end
  link :todos do |context|
    context.user_todos_url self
  end
end
# {
#   "_links": {
#     "self": {
#       "href": "http://example.com/users/8oljbpyjetu8"
#     },
#     "todos": {
#       "href": "http://example.com/users/8oljbpyjetu8/todos"
#     }
#   }
# }

Configuration options are displayed as additional properties on a link.

class UserPresenter < Jsonite
  link :todos, title: 'To-dos', templated: true do |context|
    "#{context.user_todos_url self}{?done}"
  end
end
# {
#   "_links": {
#     "todos": {
#       "href": "http://example.com/users/8oljbpyjetu8/todos{?done}",
#       "title": "To-dos",
#       "templated": true
#     }
#   }
# }


109
110
111
# File 'lib/jsonite.rb', line 109

def link rel = :self, options = {}, &handler
  links[rel.to_s] = { handler: Proc.new }.merge options # require handler
end


113
114
115
# File 'lib/jsonite.rb', line 113

def links
  @links ||= {}
end

.present(resource, options = {}) ⇒ Object

Presents a resource (or array of resources).

class UserPresenter < Jsonite
  property :email
end
users = User.all
UserPresenter.present(users.first)
# => {"email"=>"[email protected]"}
UserPresenter.present(users)
# => [{"email"=>"[email protected]"}, ...]

Configuration options:

  • :root - A root key to wrap the resource with.

  • :with - A specified presenter (defaults to ‘self`).

All other options are passed along to #present.



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/jsonite.rb', line 31

def present resource, options = {}
  presenter = options.delete(:with) { self }

  presented = if resource.is_a? Jsonite
    resource.present options
  elsif resource.respond_to?(:to_ary)
    resource.to_ary.map do |member|
      presenter.new(member).present options.merge root: nil
    end
  else
    presenter.new(resource).present options.merge root: nil
  end

  root = options.fetch(:root) { Helper.resource_name(resource) }
  root ? { root => presented } : presented
end

.properties(*properties) ⇒ Object



66
67
68
69
70
# File 'lib/jsonite.rb', line 66

def properties *properties
  @properties ||= {}
  properties.map(&method(:property)) if properties.present?
  @properties
end

.property(name, options = {}, &handler) ⇒ Object

Defines a property to be exposed during presentation.

class UserPresenter < Jsonite
  property :email
end
# {
#   "email": "[email protected]"
# }

Configuration options:

  • :with - A specified presenter. Ignored when a handler is present. Useful when you want to embed a resource as a property (rather than in the _embedded node).

  • :ignore_nil - Ignore ‘nil`.



62
63
64
# File 'lib/jsonite.rb', line 62

def property name, options = {}, &handler
  properties[name.to_s] = { handler: handler }.merge options
end

Instance Method Details

#as_json(options = {}) ⇒ Object

Returns a JSON-ready representation (Hash) of the resource.

Options:

  • :root



210
211
212
# File 'lib/jsonite.rb', line 210

def as_json options = {}
  present(options).as_json options
end

#present(options = {}) ⇒ Object

Returns a raw representation (Hash) of the resource.

Options:

  • :context - A context to pass a presenter instance while rendering properties, links, and embedded resources.



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/jsonite.rb', line 190

def present options = {}
  options = defaults.merge options

  context = options.delete :context
  proxied = LetsProxy.new resource, context, self.class.lets

  presented = properties proxied, context
  _links = links proxied, context
  presented['_links'] = _links if _links.present?
  _embedded = embedded proxied, context
  presented['_embedded'] = _embedded if _embedded.present?

  root = options.fetch(:root) { Helper.resource_name(resource) }
  root ? { root => presented } : presented
end