frill 0.1.10 → 0.1.11

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.10
1
+ 0.1.11
@@ -1,10 +1,10 @@
1
1
  module ViewContextFrill
2
2
  include Frill
3
3
 
4
- def self.frill? object, controller
4
+ def self.frill? object, context
5
5
  object.class_eval do
6
6
  define_method :helpers do
7
- @frill_helper ||= controller.view_context
7
+ @frill_helper ||= context.respond_to?(:view_context) ? context.view_context : context
8
8
  end
9
9
 
10
10
  define_method :h do
@@ -1,2 +1,3 @@
1
1
  require 'frill/frill'
2
2
  require 'frill/engine' if defined? Rails
3
+ require 'frill/rspec' if defined?(RSpec) and RSpec.respond_to?(:configure)
@@ -1,7 +1,7 @@
1
1
  module Frill
2
2
  class CyclicDependency < RuntimeError; end
3
3
 
4
- def self.included(base)
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(nodes)
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(node)
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(direction, start_node)
125
+ def fan direction, start_node
128
126
  current_node = start_node.send direction
129
127
 
130
128
  while current_node
@@ -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
@@ -32,11 +32,14 @@ module FooFrill
32
32
  end
33
33
 
34
34
  def foo
35
- h.render partial: "shared/foo", locals: { foo: "#{super} bar" }
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 before being passed off to your view.
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/MM/DD
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.strftime "%Y/%m/%d" }
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/MM/DD
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.strftime "%Y/%m/%d"
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
- super.strftime "%Y/%m/%d"
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 returned with `strftime`.
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
- For example, inside a controller:
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
- class PostsController < ApplicationController
253
- def index
254
- @posts = frill Post.all
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
- def show
258
- @post = frill Post.find(params[:id])
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
- Or, in a view:
327
+ Since frills are just modules, it's possible to test your frills in relative isolation.
264
328
 
265
- ```erb
266
- <%= render frill(@post.comments) %>
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.10
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-08-26 00:00:00.000000000 Z
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: &70295008464380 !ruby/object:Gem::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: *70295008464380
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: &70295008463160 !ruby/object:Gem::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: *70295008463160
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: &70295008458700 !ruby/object:Gem::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: *70295008458700
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: &70295008457520 !ruby/object:Gem::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: *70295008457520
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: &70295008456620 !ruby/object:Gem::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: *70295008456620
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.17
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.