frill 0.1.10 → 0.1.11
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.
- data/VERSION +1 -1
- data/app/frills/view_context_frill.rb +2 -2
- data/lib/frill.rb +1 -0
- data/lib/frill/frill.rb +4 -6
- data/lib/frill/rspec.rb +32 -0
- data/readme.markdown +153 -23
- metadata +39 -13
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.11
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module ViewContextFrill
|
2
2
|
include Frill
|
3
3
|
|
4
|
-
def self.frill? object,
|
4
|
+
def self.frill? object, context
|
5
5
|
object.class_eval do
|
6
6
|
define_method :helpers do
|
7
|
-
@frill_helper ||=
|
7
|
+
@frill_helper ||= context.respond_to?(:view_context) ? context.view_context : context
|
8
8
|
end
|
9
9
|
|
10
10
|
define_method :h do
|
data/lib/frill.rb
CHANGED
data/lib/frill/frill.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Frill
|
2
2
|
class CyclicDependency < RuntimeError; end
|
3
3
|
|
4
|
-
def self.included
|
4
|
+
def self.included base
|
5
5
|
self.dependency_graph.add base
|
6
6
|
base.extend ClassMethods
|
7
7
|
end
|
@@ -101,7 +101,7 @@ module Frill
|
|
101
101
|
new(nodes).detect!
|
102
102
|
end
|
103
103
|
|
104
|
-
def initialize
|
104
|
+
def initialize nodes
|
105
105
|
@nodes = nodes
|
106
106
|
@visited = {}
|
107
107
|
end
|
@@ -112,19 +112,17 @@ module Frill
|
|
112
112
|
end
|
113
113
|
end
|
114
114
|
|
115
|
-
|
116
115
|
private
|
117
|
-
|
118
116
|
attr_reader :nodes, :visited
|
119
117
|
|
120
|
-
def fan_out
|
118
|
+
def fan_out node
|
121
119
|
visited[node.label] = true
|
122
120
|
|
123
121
|
fan :next, node
|
124
122
|
fan :previous, node
|
125
123
|
end
|
126
124
|
|
127
|
-
def fan
|
125
|
+
def fan direction, start_node
|
128
126
|
current_node = start_node.send direction
|
129
127
|
|
130
128
|
while current_node
|
data/lib/frill/rspec.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module Frill
|
2
|
+
module RSpec
|
3
|
+
module Helpers
|
4
|
+
def frill model
|
5
|
+
view_context = ApplicationController.new.view_context.tap do |context|
|
6
|
+
context.controller.request ||= ActionController::TestRequest.new
|
7
|
+
context.request ||= context.controller.request
|
8
|
+
context.params ||= {}
|
9
|
+
end
|
10
|
+
|
11
|
+
Frill.decorate model, view_context
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module Frill
|
18
|
+
module RSpec
|
19
|
+
module ExampleGroup
|
20
|
+
def self.included(base)
|
21
|
+
base.metadata[:type] = :frill
|
22
|
+
base.send :include, Frill::RSpec::Helpers
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
RSpec.configure do |config|
|
29
|
+
config.include Frill::RSpec::ExampleGroup, :type => :frill, :example_group => {
|
30
|
+
:file_path => /spec[\\\/]frills/
|
31
|
+
}
|
32
|
+
end
|
data/readme.markdown
CHANGED
@@ -32,11 +32,14 @@ module FooFrill
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def foo
|
35
|
-
h.
|
35
|
+
h.content_tag :b, "#{super} bar"
|
36
36
|
end
|
37
37
|
end
|
38
38
|
```
|
39
39
|
|
40
|
+
The `h` method gives you access to all of the view helpers you would normally expect to use inside a view or a helper.
|
41
|
+
It's aliased to `helpers`, so feel free to use either.
|
42
|
+
|
40
43
|
Opt objects in your controllers into frill with the `frill` method:
|
41
44
|
|
42
45
|
```ruby
|
@@ -64,7 +67,8 @@ class ApplicationController < ActionController::Base
|
|
64
67
|
end
|
65
68
|
```
|
66
69
|
|
67
|
-
Now you don't need to use the `frill` method to decorate objects. They'll be automatically decorated
|
70
|
+
Now you don't need to use the `frill` method to decorate objects. They'll be automatically decorated
|
71
|
+
before being passed off to your view.
|
68
72
|
|
69
73
|
```ruby
|
70
74
|
class FooController < ApplicationController
|
@@ -74,6 +78,31 @@ class FooController < ApplicationController
|
|
74
78
|
end
|
75
79
|
```
|
76
80
|
|
81
|
+
### 'frill' decorates individual objects _and_ collections
|
82
|
+
|
83
|
+
The `frill` helper will decorate both single objects and collections of objects. You can use it both within your controller
|
84
|
+
and within your views.
|
85
|
+
|
86
|
+
For example, inside a controller:
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
class FoosController < ApplicationController
|
90
|
+
def index
|
91
|
+
@foos = frill Foo.all
|
92
|
+
end
|
93
|
+
|
94
|
+
def show
|
95
|
+
@foo = frill Foo.find(params[:id])
|
96
|
+
end
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
100
|
+
Or, in a view:
|
101
|
+
|
102
|
+
```erb
|
103
|
+
<%= render frill(@foo.comments) %>
|
104
|
+
```
|
105
|
+
|
77
106
|
## A longer story
|
78
107
|
|
79
108
|
Your product manager writes the following story for you:
|
@@ -81,12 +110,12 @@ Your product manager writes the following story for you:
|
|
81
110
|
```cucumber
|
82
111
|
Feature: Consistent Timestamp Presentation
|
83
112
|
As a user
|
84
|
-
I want "created at" timestamps presented in a uniform way on the site
|
113
|
+
I want "created at" timestamps presented in a uniform, localized way on the site
|
85
114
|
So that I can easily discover the age of content on the site
|
86
115
|
|
87
116
|
Scenario: Presenting timestamps
|
88
117
|
When I navigate to a page that displays a created_at timestamp
|
89
|
-
Then I should see that timestamp marked up as bold and formatted as follows: YYYY
|
118
|
+
Then I should see that timestamp marked up as bold and formatted for the client's locale as follows: Month DD, YYYY HH:MM
|
90
119
|
```
|
91
120
|
|
92
121
|
You see this and roll your eyes. You're thinking about all of the places that you show `created_at`
|
@@ -95,7 +124,7 @@ timestamps on the site. Reluctantly, you roll up your sleeves and start by writi
|
|
95
124
|
```ruby
|
96
125
|
module ApplicationHelper
|
97
126
|
def format_timestamp(t)
|
98
|
-
render partial: "shared/timestamp", locals: { time: t
|
127
|
+
render partial: "shared/timestamp", locals: { time: l(t, format: :long) }
|
99
128
|
end
|
100
129
|
end
|
101
130
|
```
|
@@ -127,7 +156,7 @@ Feature: Consistent Timestamp Presentation in the API
|
|
127
156
|
|
128
157
|
Scenario: Presenting timestamps
|
129
158
|
When I retrieve content with a "created_at" timestamp via the JSON API
|
130
|
-
Then I should see that timestamp formatted as follows: YYYY
|
159
|
+
Then I should see that timestamp formatted for the client's locale as follows: Month DD, YYYY HH:MM
|
131
160
|
```
|
132
161
|
|
133
162
|
You attempt to salvage the helper, updating it with concerns for the JSON format:
|
@@ -135,7 +164,7 @@ You attempt to salvage the helper, updating it with concerns for the JSON format
|
|
135
164
|
```ruby
|
136
165
|
module ApplicationHelper
|
137
166
|
def format_timestamp(t)
|
138
|
-
time = t
|
167
|
+
time = l t, format: :long
|
139
168
|
|
140
169
|
if request.format.html?
|
141
170
|
render partial: "shared/timestamp", locals: { time: time }
|
@@ -167,13 +196,15 @@ module TimestampFrill
|
|
167
196
|
end
|
168
197
|
|
169
198
|
def created_at
|
170
|
-
|
199
|
+
helpers.l super, format: :long
|
171
200
|
end
|
172
201
|
end
|
173
202
|
```
|
174
203
|
|
175
204
|
The `frill?` method tells `Frill` when to extend an object with this module. Then we redefine the `created_at` method,
|
176
|
-
calling super and then formatting the date
|
205
|
+
calling super and then formatting the date with the rails localization helper `l`. The `helpers` method is made available to
|
206
|
+
frill'ed objects; it contains the same view context that you have access to inside of views and inside of helper methods.
|
207
|
+
You can use the `h` method as well - it's simply an alias for `helpers`.
|
177
208
|
|
178
209
|
Simple enough.
|
179
210
|
|
@@ -194,13 +225,17 @@ module HtmlTimestampFrill
|
|
194
225
|
end
|
195
226
|
```
|
196
227
|
|
228
|
+
```erb
|
229
|
+
<b><%=time%></b>
|
230
|
+
```
|
231
|
+
|
197
232
|
There's three important things to note:
|
198
233
|
|
199
234
|
1. This frill comes after `TimestampFrill`. That tells `Frill` that it should only attempt to extend an object with this module after attempting to extend it with `TimestampFrill`.
|
200
235
|
1. The `frill?` method only returns true if it's an HTML request, meaning this frill won't be extended onto objects for your JSON api.
|
201
236
|
1. The `h` method gives you access to all of the normal view helper methods you expect to you use inside your views. You can also use `helpers`.
|
202
237
|
|
203
|
-
Lastly, opt objects into frilling inside your controllers:
|
238
|
+
Lastly, opt objects into frilling inside your controllers by using the `frill` method:
|
204
239
|
|
205
240
|
```ruby
|
206
241
|
class ArticlesController < ApplicationController
|
@@ -218,7 +253,7 @@ frill will attempt to extend the object with any applicable frills (i.e., frills
|
|
218
253
|
|
219
254
|
That way, you can simply render your `created_at` attributes without any helpers, and they will automatically present themselves appropriately for their context (e.g., HTML v. JSON requests).
|
220
255
|
|
221
|
-
Note that if prefer, you can configure your controllers to automatically frill all objects for presentation by calling the `auto_frill` method inside your `ApplicationController`, instead of manually having to opt them it via the `frill` method:
|
256
|
+
Note that if you prefer, you can configure your controllers to automatically frill all objects for presentation by calling the `auto_frill` method inside your `ApplicationController`, instead of manually having to opt them it via the `frill` method:
|
222
257
|
|
223
258
|
```ruby
|
224
259
|
class ApplicationController < ActionController::Base
|
@@ -241,31 +276,126 @@ end
|
|
241
276
|
|
242
277
|
Now, any instance variables you create in your controllers will be automatically frilled before handed off to your views.
|
243
278
|
|
244
|
-
### 'frill' decorates individual objects _and_ collections
|
245
279
|
|
246
|
-
As I've hinted at, the `frill` helper will decorate both single objects and collections of objects. You can use it both within your controller
|
247
|
-
and within your views.
|
248
280
|
|
249
|
-
|
281
|
+
## Testing
|
282
|
+
|
283
|
+
If you're using frill inside a Rails application, you can take advantage of the "frill" rspec helper:
|
250
284
|
|
251
285
|
```ruby
|
252
|
-
|
253
|
-
|
254
|
-
|
286
|
+
require 'spec_helper'
|
287
|
+
|
288
|
+
describe HtmlTimestampFrill do
|
289
|
+
let(:model) {
|
290
|
+
Class.new do
|
291
|
+
def created_at
|
292
|
+
DateTime.new(2012, 1, 1)
|
293
|
+
end
|
294
|
+
end.new
|
255
295
|
end
|
256
296
|
|
257
|
-
|
258
|
-
|
297
|
+
subject { frill model }
|
298
|
+
|
299
|
+
its(:created_at) { should == "<b>January 01, 2012 00:00<b>" }
|
300
|
+
end
|
301
|
+
```
|
302
|
+
|
303
|
+
It will assume an html request context, and it will embue your model with `h` and `helpers` methods.
|
304
|
+
|
305
|
+
If you're attempting to test the `MyFrill.frill?` method, you'll need to supply it with stubs:
|
306
|
+
|
307
|
+
```ruby
|
308
|
+
require 'spec_helper'
|
309
|
+
|
310
|
+
describe HtmlTimestampFrill do
|
311
|
+
let(:context) { double :view_context }
|
312
|
+
|
313
|
+
subject { HtmlTimestampFrill.frill? double(:model, created_at: "foo"), context }
|
314
|
+
|
315
|
+
context "given an HTML request" do
|
316
|
+
before { context.stub_chain(:request, :format, :html?).and_return true }
|
317
|
+
it { should be_true }
|
318
|
+
end
|
319
|
+
|
320
|
+
context "given a non-HTML request" do
|
321
|
+
before { context.stub_chain(:request, :format, :html?).and_return false }
|
322
|
+
it { should be_false }
|
259
323
|
end
|
260
324
|
end
|
261
325
|
```
|
262
326
|
|
263
|
-
|
327
|
+
Since frills are just modules, it's possible to test your frills in relative isolation.
|
264
328
|
|
265
|
-
```
|
266
|
-
|
329
|
+
```ruby
|
330
|
+
require 'spec_helper'
|
331
|
+
|
332
|
+
describe TimestampFrill do
|
333
|
+
let(:object) do
|
334
|
+
double :object,
|
335
|
+
created_at: DateTime.new(2012, 1, 1),
|
336
|
+
h: ApplicationController.new.view_context
|
337
|
+
end
|
338
|
+
|
339
|
+
subject { object.extend TimestampFrill }
|
340
|
+
|
341
|
+
its(:created_at) { should == "January 01, 2012 00:00" }
|
342
|
+
end
|
343
|
+
```
|
344
|
+
|
345
|
+
When it comes to view methods that render partials, etc., you could choose to test them with integration:
|
346
|
+
|
347
|
+
```ruby
|
348
|
+
require 'spec_helper'
|
349
|
+
|
350
|
+
class SomeModel
|
351
|
+
def h
|
352
|
+
@view_context ||= ApplicationController.new.view_context
|
353
|
+
end
|
354
|
+
|
355
|
+
def created_at
|
356
|
+
Time.new(2012,1,1)
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
describe HtmlTimestampFrill do
|
361
|
+
let(:object) { SomeModel.new.extend TimestampFrill }
|
362
|
+
|
363
|
+
subject { object.extend HtmlTimestampFrill }
|
364
|
+
|
365
|
+
describe "#created_at" do
|
366
|
+
it "should render the timestamp partial" do
|
367
|
+
subject.created_at.strip.should == "<b>January 01, 2012 00:00</b>"
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
267
371
|
```
|
268
372
|
|
373
|
+
Or you could test them by stubbing out the view context, and simply setting up expectations on them:
|
374
|
+
|
375
|
+
```ruby
|
376
|
+
require 'spec_helper'
|
377
|
+
|
378
|
+
class SomeModel
|
379
|
+
def h; end
|
380
|
+
def created_at; end
|
381
|
+
end
|
382
|
+
|
383
|
+
describe HtmlTimestampFrill do
|
384
|
+
let(:object) { SomeModel.new }
|
385
|
+
|
386
|
+
subject { object.extend HtmlTimestampFrill }
|
387
|
+
|
388
|
+
describe "#created_at" do
|
389
|
+
it "should render the timestamp partial" do
|
390
|
+
subject.h.should_receive(:render)
|
391
|
+
subject.created_at
|
392
|
+
end
|
393
|
+
end
|
394
|
+
end
|
395
|
+
```
|
396
|
+
|
397
|
+
The latter can be nice if you're really just interested in testing conditional logic inside your decoration.
|
398
|
+
|
269
399
|
## Usage outside Rails
|
270
400
|
|
271
401
|
There are really just three integrations in a Rails app: the `frill`
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: frill
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.11
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-09-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,15 @@ dependencies:
|
|
21
21
|
version: 3.2.2
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.2.2
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: rspec
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ! '>='
|
@@ -32,10 +37,15 @@ dependencies:
|
|
32
37
|
version: '0'
|
33
38
|
type: :development
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
47
|
name: rspec-rails
|
38
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
39
49
|
none: false
|
40
50
|
requirements:
|
41
51
|
- - ! '>='
|
@@ -43,10 +53,15 @@ dependencies:
|
|
43
53
|
version: '0'
|
44
54
|
type: :development
|
45
55
|
prerelease: false
|
46
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
47
62
|
- !ruby/object:Gem::Dependency
|
48
63
|
name: capybara
|
49
|
-
requirement:
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
50
65
|
none: false
|
51
66
|
requirements:
|
52
67
|
- - ! '>='
|
@@ -54,10 +69,15 @@ dependencies:
|
|
54
69
|
version: '0'
|
55
70
|
type: :development
|
56
71
|
prerelease: false
|
57
|
-
version_requirements:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
58
78
|
- !ruby/object:Gem::Dependency
|
59
79
|
name: pry
|
60
|
-
requirement:
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
61
81
|
none: false
|
62
82
|
requirements:
|
63
83
|
- - ! '>='
|
@@ -65,7 +85,12 @@ dependencies:
|
|
65
85
|
version: '0'
|
66
86
|
type: :development
|
67
87
|
prerelease: false
|
68
|
-
version_requirements:
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
69
94
|
description:
|
70
95
|
email: moonmaster9000@gmail.com
|
71
96
|
executables: []
|
@@ -75,6 +100,7 @@ files:
|
|
75
100
|
- lib/frill/engine.rb
|
76
101
|
- lib/frill/frill.rb
|
77
102
|
- lib/frill/rails.rb
|
103
|
+
- lib/frill/rspec.rb
|
78
104
|
- lib/frill.rb
|
79
105
|
- lib/generators/frill/frill_generator.rb
|
80
106
|
- lib/generators/frill/templates/frill.rb
|
@@ -106,7 +132,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
106
132
|
version: '0'
|
107
133
|
requirements: []
|
108
134
|
rubyforge_project:
|
109
|
-
rubygems_version: 1.8.
|
135
|
+
rubygems_version: 1.8.24
|
110
136
|
signing_key:
|
111
137
|
specification_version: 3
|
112
138
|
summary: Decorating objects for presentation. Supports Rails out of the box.
|