halogen 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 491dfa5f8eb8f51c4973205d1fbab6e883ce40db
4
+ data.tar.gz: 79c6b3b9b20ba7e86b6684daa38440b60b34460c
5
+ SHA512:
6
+ metadata.gz: a69872769a3355f338b642ff0ae66dcbbc37a76edb9e74f7826e3abf7c53d8525ef8399a042db3d4d38b971d3bd7851984395779af628cd1df99e10983224024
7
+ data.tar.gz: d6ba44f85ce1d6b5bf1108975aa3426354f8f1b32d3cfc62bd16d91d9f894ac14e8186d8ca6121a561d0e5659cef16b7a81c9421ea386328421329c98c5b4b06
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ *.gem
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - '2.0'
5
+ - '2.1'
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in halogen.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Heather Rivers
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,244 @@
1
+ # Halogen
2
+
3
+ [![Build Status](https://travis-ci.org/mode/halogen.svg)](https://travis-ci.org/mode/halogen)
4
+
5
+ This library provides a framework-agnostic interface for generating
6
+ [HAL+JSON](http://stateless.co/hal_specification.html)
7
+ representations of resources in Ruby.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'halogen'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install halogen
24
+
25
+ ## Usage
26
+
27
+ ### Basic usage
28
+
29
+ Create a simple representer class and include Halogen:
30
+
31
+ ```ruby
32
+ class GoatRepresenter
33
+ include Halogen
34
+
35
+ property :name do
36
+ 'Gideon'
37
+ end
38
+
39
+ link :self do
40
+ '/goats/gideon'
41
+ end
42
+ end
43
+ ```
44
+
45
+ Instantiate:
46
+
47
+ ```ruby
48
+ repr = GoatRepresenter.new
49
+ ```
50
+
51
+ Then call `repr.render`:
52
+
53
+ ```ruby
54
+ {
55
+ name: 'Gideon',
56
+ _links: {
57
+ self: { href: '/goats/gideon' }
58
+ }
59
+ }
60
+ ```
61
+
62
+ Or `repr.to_json`:
63
+
64
+ ```ruby
65
+ '{"name": "Gideon", "_links": {"self": {"href": "/goats/gideon"}}}'
66
+ ```
67
+
68
+ ### Representer types
69
+
70
+ #### 1. Simple
71
+
72
+ Not associated with any particular resource or collection. For example, an API
73
+ entry point:
74
+
75
+ ```ruby
76
+ class ApiRootRepresenter
77
+ include Halogen
78
+
79
+ link(:self) { '/api' }
80
+ end
81
+ ```
82
+
83
+ #### 2. Resource
84
+
85
+ Represents a single item:
86
+
87
+ ```ruby
88
+ class GoatRepresenter
89
+ include Halogen
90
+
91
+ resource :goat
92
+ end
93
+ ```
94
+
95
+ When a resource is declared, `#initialize` expects the resource as the first argument:
96
+
97
+ ```ruby
98
+ repr = GoatRepresenter.new(Goat.new, ...)
99
+ ```
100
+
101
+ This makes property definitions cleaner:
102
+
103
+ ```ruby
104
+ property :name # now calls Goat#name by default
105
+ ```
106
+
107
+ #### 3. Collection
108
+
109
+ Represents a collection of items. When a collection is declared, the embedded
110
+ resource with the same name will always be embedded, whether it is requested
111
+ via standard embed options or not.
112
+
113
+ ```ruby
114
+ class GoatKidsRepresenter
115
+ include Halogen
116
+
117
+ collection :kids
118
+
119
+ embed(:kids) { ... } # always embedded
120
+ end
121
+ ```
122
+
123
+ ### Defining properties, links and embeds
124
+
125
+ Properties can be defined in several ways:
126
+
127
+ ```ruby
128
+ property(:age) { "#{goat.age} years old" }
129
+ ```
130
+
131
+ ```ruby
132
+ property :age # => Goat#age, if resource is declared
133
+ ```
134
+
135
+ ```ruby
136
+ property :age do
137
+ goat.age.round
138
+ end
139
+ ```
140
+
141
+ ```ruby
142
+ property(:age) { calculate_age }
143
+
144
+ def calculate_age
145
+ ...
146
+ end
147
+ ```
148
+
149
+ #### Conditionals
150
+
151
+ The inclusion of properties can be determined by conditionals using `if` and
152
+ `unless` options. For example, with a method name:
153
+
154
+ ```ruby
155
+ property :age, if: :include_age?
156
+
157
+ def include_age?
158
+ goat.age < 10
159
+ end
160
+ ```
161
+
162
+ With a proc:
163
+ ```ruby
164
+ property :age, unless: proc { goat.age.nil? }, value: ...
165
+ ```
166
+
167
+ For links and embeds:
168
+
169
+ ```ruby
170
+ link :kids, :templated, unless: :exclude_kids_link?, value: ...
171
+ ```
172
+
173
+ ```ruby
174
+ embed :kids, if: proc { goat.kids.size > 0 } do
175
+ ...
176
+ end
177
+ ```
178
+
179
+ #### Links
180
+
181
+ Simple link:
182
+
183
+ ```ruby
184
+ link(:root) { '/' }
185
+ # => { _links: { root: { href: '/' } } ... }
186
+ ```
187
+
188
+ Templated link:
189
+
190
+ ```ruby
191
+ link(:find, :templated) { '/goats/{?id}' }
192
+ # => { _links: { find: { href: '/goats/{?id}', templated: true } } ... }
193
+ ```
194
+
195
+ ### Embedded resources
196
+
197
+ Embedded resources are not rendered by default. They will be included if both
198
+ of the following conditions are met:
199
+
200
+ 1. The proc returns either a Halogen instance or an array of Halogen instances
201
+ 2. The embed is requested via the parent representer's options, e.g.:
202
+
203
+ ```ruby
204
+ GoatRepresenter.new(embed: { kids: true, parents: false })
205
+ ```
206
+
207
+ Embedded resources can be nested to any depth, e.g.:
208
+
209
+ ```ruby
210
+ GoatRepresenter.new(embed: {
211
+ kids: {
212
+ foods: {
213
+ ingredients: true
214
+ },
215
+ pasture: true
216
+ }
217
+ })
218
+ ```
219
+
220
+ ### Using with Rails
221
+
222
+ If Halogen is loaded in a Rails application, Rails url helpers will be
223
+ available in representers:
224
+
225
+ ```ruby
226
+ link(:new) { new_goat_url }
227
+ ```
228
+
229
+ ### More examples
230
+
231
+ * [Full representer class](examples/simple.rb)
232
+ * [Extensions](examples/extensions.md)
233
+
234
+ ### What's with the goat?
235
+
236
+ It is [majestic](https://twitter.com/ModeAnalytics/status/497876416013537280).
237
+
238
+ ## Contributing
239
+
240
+ 1. Fork it ( https://github.com/mode/halogen/fork )
241
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
242
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
243
+ 4. Push to the branch (`git push origin my-new-feature`)
244
+ 5. Create a new Pull Request
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,25 @@
1
+ # Extensions
2
+
3
+ You can extend Halogen by configuring it to include your own Ruby modules.
4
+
5
+ For instance, if you wanted to cache the rendered versions of your
6
+ representers, you might use something like this to override the default
7
+ `#render` behavior:
8
+
9
+ ```ruby
10
+ module MyCachingExtension
11
+ def render
12
+ Rails.cache.fetch(cache_key) { super }
13
+ end
14
+
15
+ def cache_key
16
+ ...
17
+ end
18
+ end
19
+ ```
20
+
21
+ ```ruby
22
+ Halogen.configure do |config|
23
+ config.extensions << MyCachingExtension
24
+ end
25
+ ```
@@ -0,0 +1,142 @@
1
+ # encoding: utf-8
2
+ #
3
+ $LOAD_PATH.unshift(File.expand_path('../lib', File.dirname(__FILE__)))
4
+
5
+ require 'halogen'
6
+ require 'pp'
7
+
8
+ # Example of a straightforward Halogen representer with no resource,
9
+ # collection, or conditional definitions
10
+ #
11
+ class GoatRepresenter
12
+ include Halogen
13
+
14
+ # Simple instance methods that will be used for properties below
15
+ #
16
+ def id; 1; end
17
+ def first_name; 'Gideon'; end
18
+ def last_name; 'Goat'; end
19
+
20
+ # == 1. Properties
21
+ #
22
+ # If you define a property without an explicit value or proc, Halogen will
23
+ # look for a public instance method with the corresponding name.
24
+ #
25
+ # This will call GoatRepresenter#id.
26
+ #
27
+ property :id # => { id: 1 }
28
+
29
+ # You can also define a property with an explicit value, e.g.:
30
+ #
31
+ property :age, value: 9.2 # => { age: 9.2 }
32
+
33
+ # Or you can use a proc to determine the property value at render time.
34
+ #
35
+ # The example below could also be written: property(:full_name) { ... }
36
+ #
37
+ property :full_name do # => { full_name: 'Gideon Goat' }
38
+ "#{first_name} #{last_name}"
39
+ end
40
+
41
+ # == 2. Links
42
+ #
43
+ # As with properties, links can be defined with a proc:
44
+ #
45
+ link :self do
46
+ "/goats/#{id}" # => { self: { href: '/goats/1' } }
47
+ end
48
+
49
+ # ...Or with an explicit value:
50
+ #
51
+ link :root, value: '/goats' # => { root: { href: '/goats' } }
52
+
53
+ # Links can also be defined as "templated", following HAL+JSON conventions:
54
+ #
55
+ link :find, :templated do # => ... { href: '/goats/{?id}', templated: true }
56
+ '/goats/{?id}'
57
+ end
58
+
59
+ # If Halogen is loaded in a Rails application, url helpers will be available
60
+ # automatically:
61
+ #
62
+ # link(:new) { new_goat_path }
63
+
64
+ # == 3. Embeds
65
+ #
66
+ # Embedded resources are not rendered by default. They will be included if
67
+ # both of the following conditions are met:
68
+ #
69
+ # 1. The proc returns either a Halogen instance or an array of Halogen instances
70
+ # 2. The embed is requested via the parent representer's options, e.g.:
71
+ #
72
+ # GoatRepresenter.new(embed: { kids: true, parents: false })
73
+ #
74
+ embed :kids do # => { kids: <GoatKidsRepresenter#render> }
75
+ GoatKidsRepresenter.new
76
+ end
77
+
78
+ embed :parents do # => will not be included according to example options above
79
+ [
80
+ self.class.new,
81
+ self.class.new
82
+ ]
83
+ end
84
+
85
+ # Embedded resources can be nested to any depth, e.g.:
86
+ #
87
+ # GoatRepresenter.new(embed: {
88
+ # kids: {
89
+ # foods: {
90
+ # ingredients: true
91
+ # },
92
+ # enclosure: true
93
+ # }
94
+ # })
95
+ end
96
+
97
+ # Another simple representer to demonstrate embedded resources above
98
+ #
99
+ class GoatKidsRepresenter
100
+ include Halogen
101
+
102
+ property :count, value: 5
103
+ end
104
+
105
+ puts 'GoatRepresenter.new(embed: { kids: true }).render:'
106
+ puts
107
+ pp GoatRepresenter.new(embed: { kids: true }).render
108
+ #
109
+ # Result:
110
+ #
111
+ # {
112
+ # id: 1,
113
+ # age: 9.2,
114
+ # full_name: "Gideon Goat",
115
+ # _embedded: {
116
+ # kids: { count: 5 }
117
+ # },
118
+ # _links: {
119
+ # self: { href: '/goats/1' },
120
+ # root: { href: '/goats"'},
121
+ # find: { href: '/goats/{?id}', templated: true }
122
+ # }
123
+ # }
124
+ #
125
+
126
+ puts
127
+ puts 'GoatRepresenter.new.render:'
128
+ puts
129
+ pp GoatRepresenter.new.render
130
+ #
131
+ # Result:
132
+ #
133
+ # {
134
+ # id: 1,
135
+ # age: 9.2,
136
+ # full_name: "Gideon Goat",
137
+ # _links: {
138
+ # self: { href: '/goats/1' },
139
+ # root: { href: '/goats"'},
140
+ # find: { href: '/goats/{?id}', templated: true }
141
+ # }
142
+ # }