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 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.