cells 4.0.0.beta6 → 4.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +4 -0
- data/README.md +316 -371
- data/cells.gemspec +1 -3
- data/lib/cell/caching.rb +1 -0
- data/lib/cell/rails.rb +7 -0
- data/lib/cell/railtie.rb +2 -5
- data/lib/cell/version.rb +1 -1
- data/lib/cell/view_model.rb +24 -30
- data/test/builder_test.rb +10 -7
- data/test/caching_test.rb +47 -40
- data/test/rails4.2/app/cells/song_cell.rb +7 -0
- data/test/rails4.2/app/controllers/songs_controller.rb +8 -0
- data/test/rails4.2/test/integration/formtastic_test.rb +1 -0
- data/test/rails4.2/test/integration/simple_form_test.rb +1 -0
- data/test/rails4.2/test/integration/url_helper_test.rb +16 -5
- data/test/templates_test.rb +1 -1
- data/test/test_helper.rb +2 -0
- data/test/twin_test.rb +20 -20
- metadata +4 -18
data/cells.gemspec
CHANGED
@@ -21,12 +21,10 @@ Gem::Specification.new do |spec|
|
|
21
21
|
|
22
22
|
spec.add_dependency "uber", "~> 0.0.9"
|
23
23
|
spec.add_dependency 'tilt', '>= 1.4', '< 3'
|
24
|
-
spec.add_dependency 'disposable', '~> 0.0.8'
|
25
|
-
|
26
24
|
|
27
25
|
spec.add_development_dependency "rake"
|
28
26
|
spec.add_development_dependency "minitest-reporters"
|
29
27
|
spec.add_development_dependency "capybara"
|
30
28
|
|
31
|
-
spec.add_development_dependency "cells-erb", ">= 0.0.
|
29
|
+
spec.add_development_dependency "cells-erb", ">= 0.0.4"
|
32
30
|
end
|
data/lib/cell/caching.rb
CHANGED
data/lib/cell/rails.rb
CHANGED
@@ -34,6 +34,13 @@ module Cell
|
|
34
34
|
module ViewModel
|
35
35
|
extend ActiveSupport::Concern
|
36
36
|
|
37
|
+
# DISCUSS: who actually uses forgery protection with cells? it is not working since 4, anyway?
|
38
|
+
# include ActionController::RequestForgeryProtection
|
39
|
+
included do
|
40
|
+
extend Uber::Delegates
|
41
|
+
delegates :parent_controller, :session, :params, :request, :config, :env, :url_options
|
42
|
+
end
|
43
|
+
|
37
44
|
def call(*)
|
38
45
|
super.html_safe
|
39
46
|
end
|
data/lib/cell/railtie.rb
CHANGED
@@ -11,10 +11,6 @@ module Cell
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
# initializer 'cells.template_engine' do |app|
|
15
|
-
# ViewModel.template_engine = app.config.app_generators.rails.fetch(:template_engine, 'erb').to_s
|
16
|
-
# end
|
17
|
-
|
18
14
|
# ruthlessly stolen from the zurb-foundation gem.
|
19
15
|
initializer 'cells.update_asset_paths' do |app|
|
20
16
|
Array(app.config.cells.with_assets).each do |cell_class|
|
@@ -38,7 +34,7 @@ module Cell
|
|
38
34
|
end
|
39
35
|
|
40
36
|
initializer "cells.include_default_helpers" do
|
41
|
-
#include
|
37
|
+
# include asset helpers (image_path, font_path, ect)
|
42
38
|
ViewModel.class_eval do
|
43
39
|
include ActionView::Helpers::UrlHelper
|
44
40
|
include ::Cell::RailsExtensions::HelpersAreShit
|
@@ -58,6 +54,7 @@ module Cell
|
|
58
54
|
ViewModel.send(:include, Cell::Haml) if Cell.const_defined?(:Haml)
|
59
55
|
ViewModel.send(:include, Cell::Slim) if Cell.const_defined?(:Slim)
|
60
56
|
end
|
57
|
+
# ViewModel.template_engine = app.config.app_generators.rails.fetch(:template_engine, 'erb').to_s
|
61
58
|
|
62
59
|
initializer('cells.development') do |app|
|
63
60
|
if Rails.env == "development"
|
data/lib/cell/version.rb
CHANGED
data/lib/cell/view_model.rb
CHANGED
@@ -1,9 +1,3 @@
|
|
1
|
-
# no helper_method calls
|
2
|
-
# no instance variables
|
3
|
-
# no locals
|
4
|
-
# options are automatically made instance methods via constructor.
|
5
|
-
# call "helpers" in class
|
6
|
-
|
7
1
|
# TODO: warn when using ::property but not passing in model in constructor.
|
8
2
|
module Cell
|
9
3
|
class ViewModel
|
@@ -36,29 +30,21 @@ module Cell
|
|
36
30
|
@controller_path ||= util.underscore(name.sub(/Cell$/, ''))
|
37
31
|
end
|
38
32
|
|
39
|
-
# FIXME: this is all rails-only.
|
40
|
-
# DISCUSS: who actually uses forgery protection with cells? it is not working since 4, anyway?
|
41
|
-
# include ActionController::RequestForgeryProtection
|
42
|
-
delegates :parent_controller, :session, :params, :request, :config, :env, :url_options
|
43
|
-
|
44
33
|
attr_reader :model
|
45
34
|
|
46
35
|
|
47
36
|
module Helpers
|
37
|
+
# Constantizes name, call builders and returns instance.
|
38
|
+
def cell(name, *args, &block) # classic Rails fuzzy API.
|
39
|
+
class_from_cell_name(name).(*args, &block)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
48
43
|
# Renders collection of cells.
|
49
|
-
def
|
44
|
+
def render_collection(array, options) # private.
|
50
45
|
method = options.delete(:method) || :show
|
51
46
|
join = options.delete(:collection_join)
|
52
|
-
array.collect { |model|
|
53
|
-
end
|
54
|
-
|
55
|
-
# Returns cell instance.
|
56
|
-
def cell(name, model=nil, options={}, &block) # classic Rails fuzzy API.
|
57
|
-
if model.is_a?(Hash) and array = model.delete(:collection)
|
58
|
-
return _collection(name, array, model.merge(options))
|
59
|
-
end
|
60
|
-
|
61
|
-
cell_for(name, model, options, &block)
|
47
|
+
array.collect { |model| build(*[model, options]).call(method) }.join(join).html_safe
|
62
48
|
end
|
63
49
|
end
|
64
50
|
extend Helpers
|
@@ -71,18 +57,25 @@ module Cell
|
|
71
57
|
|
72
58
|
include Helpers
|
73
59
|
|
74
|
-
#
|
60
|
+
# Public entry point. Use this to instantiate cells with builders.
|
61
|
+
#
|
62
|
+
# SongCell.(@song)
|
63
|
+
# SongCell.(collection: Song.all)
|
64
|
+
def call(model=nil, options={}, &block)
|
65
|
+
if model.is_a?(Hash) and array = model.delete(:collection)
|
66
|
+
return render_collection(array, model.merge(options))
|
67
|
+
end
|
75
68
|
|
76
|
-
|
77
|
-
class_from_cell_name(name).build_cell(*args)
|
69
|
+
build(model, options)
|
78
70
|
end
|
79
71
|
|
80
|
-
def
|
81
|
-
|
72
|
+
def build(*args) # semi-public.
|
73
|
+
class_builder.call(*args).new(*args) # Uber::Builder::class_builder.
|
82
74
|
end
|
83
75
|
|
84
|
-
|
85
|
-
|
76
|
+
private
|
77
|
+
def class_from_cell_name(name)
|
78
|
+
"#{name}_cell".classify.constantize
|
86
79
|
end
|
87
80
|
end
|
88
81
|
|
@@ -185,10 +178,11 @@ module Cell
|
|
185
178
|
module TemplateFor
|
186
179
|
def find_template(options)
|
187
180
|
template_options = template_options_for(options) # imported by Erb, Haml, etc.
|
181
|
+
# required options: :template_class, :suffix. everything else is passed to the template implementation.
|
188
182
|
|
189
183
|
view = options[:view]
|
190
184
|
prefixes = options[:prefixes]
|
191
|
-
suffix = template_options
|
185
|
+
suffix = template_options.delete(:suffix)
|
192
186
|
view = "#{view}.#{suffix}"
|
193
187
|
|
194
188
|
template_for(prefixes, view, template_options) or raise TemplateMissingError.new(prefixes, view)
|
data/test/builder_test.rb
CHANGED
@@ -34,25 +34,28 @@ class BuilderTest < MiniTest::Spec
|
|
34
34
|
end
|
35
35
|
|
36
36
|
# the original class is used when no builder matches.
|
37
|
-
it {
|
37
|
+
it { SongCell.(Song.new("Nation States"), {}).must_be_instance_of SongCell }
|
38
38
|
|
39
39
|
it do
|
40
|
-
cell =
|
41
|
-
cell.must_be_instance_of
|
40
|
+
cell = SongCell.(Hit.new("New York"), {})
|
41
|
+
cell.must_be_instance_of HitCell
|
42
42
|
cell.options.must_equal({})
|
43
43
|
end
|
44
44
|
|
45
45
|
it do
|
46
|
-
cell =
|
47
|
-
cell.must_be_instance_of
|
46
|
+
cell = SongCell.(Song.new("San Francisco"), evergreen: true)
|
47
|
+
cell.must_be_instance_of EvergreenCell
|
48
48
|
cell.options.must_equal({:evergreen=>true})
|
49
49
|
end
|
50
50
|
|
51
|
+
# without arguments.
|
52
|
+
it { SongCell.(Hit.new("Frenzy")).must_be_instance_of HitCell }
|
53
|
+
|
51
54
|
# with collection.
|
52
|
-
it {
|
55
|
+
it { SongCell.(collection: [Song.new("Nation States"), Hit.new("New York")]).must_equal "* Nation States* **New York**" }
|
53
56
|
|
54
57
|
# with Concept
|
55
58
|
class Track < Cell::Concept
|
56
59
|
end
|
57
|
-
it {
|
60
|
+
it { Track.().must_be_instance_of Track }
|
58
61
|
end
|
data/test/caching_test.rb
CHANGED
@@ -140,91 +140,98 @@ class CachingTest < MiniTest::Spec
|
|
140
140
|
end
|
141
141
|
|
142
142
|
# let (:cell) { DirectorCell.new(nil) }
|
143
|
-
def
|
143
|
+
def director_cell(*args)
|
144
144
|
DirectorCell.new(*args)
|
145
145
|
end
|
146
146
|
|
147
147
|
# no caching when turned off.
|
148
148
|
it do
|
149
|
-
|
149
|
+
director_cell.class.cache :show
|
150
150
|
ActionController::Base.perform_caching = false
|
151
151
|
|
152
|
-
|
153
|
-
|
152
|
+
director_cell(1).call.must_equal "1"
|
153
|
+
director_cell(2).call.must_equal "2"
|
154
154
|
end
|
155
155
|
|
156
156
|
# cache forever when no options.
|
157
157
|
it do
|
158
|
-
|
159
|
-
|
160
|
-
|
158
|
+
director_cell.class.cache :show
|
159
|
+
director_cell(1).call.must_equal "1"
|
160
|
+
director_cell(2).call.must_equal "1"
|
161
|
+
end
|
162
|
+
|
163
|
+
# caches with string state name.
|
164
|
+
it do
|
165
|
+
director_cell.class.cache :show
|
166
|
+
director_cell(1).("show").must_equal "1"
|
167
|
+
director_cell(2).("show").must_equal "1"
|
161
168
|
end
|
162
169
|
|
163
170
|
|
164
171
|
# no caching when state not configured.
|
165
172
|
it do
|
166
|
-
|
173
|
+
director_cell.class.class_eval do
|
167
174
|
def dictate
|
168
175
|
@counter
|
169
176
|
end
|
170
177
|
end
|
171
178
|
|
172
|
-
|
173
|
-
|
179
|
+
director_cell(1).call(:dictate).must_equal "1"
|
180
|
+
director_cell(2).call(:dictate).must_equal "2"
|
174
181
|
end
|
175
182
|
|
176
183
|
# compute key with cell properties from #initialize.
|
177
184
|
it do
|
178
|
-
|
185
|
+
director_cell.class.cache :show do
|
179
186
|
@counter < 3 ? {:count => "<"} : {:count => ">"}
|
180
187
|
end
|
181
188
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
189
|
+
director_cell(1).call.must_equal "1"
|
190
|
+
director_cell(2).call.must_equal "1"
|
191
|
+
director_cell(3).call.must_equal "3"
|
192
|
+
director_cell(4).call.must_equal "3"
|
186
193
|
end
|
187
194
|
|
188
195
|
# compute key with instance method
|
189
196
|
it do
|
190
|
-
|
191
|
-
|
197
|
+
director_cell.class.cache :show, :version
|
198
|
+
director_cell.class.class_eval do
|
192
199
|
def version
|
193
200
|
@counter < 3 ? {:count => "<"} : {:count => ">"}
|
194
201
|
end
|
195
202
|
end
|
196
203
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
204
|
+
director_cell(1).call.must_equal "1"
|
205
|
+
director_cell(2).call.must_equal "1"
|
206
|
+
director_cell(3).call.must_equal "3"
|
207
|
+
director_cell(4).call.must_equal "3"
|
201
208
|
end
|
202
209
|
|
203
210
|
# allow returning strings for key
|
204
211
|
it do
|
205
|
-
|
212
|
+
director_cell.class.cache :show do
|
206
213
|
@counter < 3 ? "<" : ">"
|
207
214
|
end
|
208
215
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
216
|
+
director_cell(1).call.must_equal "1"
|
217
|
+
director_cell(2).call.must_equal "1"
|
218
|
+
director_cell(3).call.must_equal "3"
|
219
|
+
director_cell(4).call.must_equal "3"
|
213
220
|
end
|
214
221
|
|
215
222
|
# allows conditional ifs.
|
216
223
|
it do
|
217
|
-
|
224
|
+
director_cell.class.cache :show, if: lambda { @counter < 3 }
|
218
225
|
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
226
|
+
director_cell(1).call.must_equal "1"
|
227
|
+
director_cell(2).call.must_equal "1"
|
228
|
+
director_cell(3).call.must_equal "3"
|
229
|
+
director_cell(4).call.must_equal "4"
|
223
230
|
end
|
224
231
|
|
225
232
|
# allows conditional ifs with instance method.
|
226
233
|
it do
|
227
|
-
|
234
|
+
director_cell.class.class_eval do
|
228
235
|
cache :show, if: :smaller?
|
229
236
|
|
230
237
|
def smaller?
|
@@ -232,22 +239,22 @@ class CachingTest < MiniTest::Spec
|
|
232
239
|
end
|
233
240
|
end
|
234
241
|
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
242
|
+
director_cell(1).call.must_equal "1"
|
243
|
+
director_cell(2).call.must_equal "1"
|
244
|
+
director_cell(3).call.must_equal "3"
|
245
|
+
director_cell(4).call.must_equal "4"
|
239
246
|
end
|
240
247
|
|
241
248
|
|
242
249
|
unless ::ActionPack::VERSION::MAJOR == 3 and ::ActionPack::VERSION::MINOR >= 2 # bug in 3.2.
|
243
250
|
describe "utf-8" do
|
244
251
|
before do
|
245
|
-
@key =
|
252
|
+
@key = director_cell.class.state_cache_key(:utf8)
|
246
253
|
end
|
247
254
|
|
248
255
|
it "has the correct encoding when reading from cache" do
|
249
|
-
assert_equal "UTF-8",
|
250
|
-
assert_equal "UTF-8",
|
256
|
+
assert_equal "UTF-8", director_cell.call(:utf8).encoding.to_s
|
257
|
+
assert_equal "UTF-8", director_cell.cache_store.read(@key).encoding.to_s
|
251
258
|
end
|
252
259
|
end
|
253
260
|
end
|
@@ -264,7 +271,7 @@ class CachingTest < MiniTest::Spec
|
|
264
271
|
end
|
265
272
|
|
266
273
|
it do
|
267
|
-
cellule = self.
|
274
|
+
cellule = self.director_cell
|
268
275
|
|
269
276
|
cellule.instance_eval do
|
270
277
|
def cache_store;
|
@@ -2,4 +2,11 @@ class SongCell < Cell::ViewModel
|
|
2
2
|
def show
|
3
3
|
"happy"
|
4
4
|
end
|
5
|
+
|
6
|
+
# include ActionView::Helpers::AssetUrlHelper
|
7
|
+
# include Sprockets::Rails::Helper
|
8
|
+
|
9
|
+
# self.assets_prefix = Rails.application.config.assets.prefix
|
10
|
+
# self.assets_environment = Rails.application.assets
|
11
|
+
# self.digest_assets = Rails.application.config.assets[:digest]
|
5
12
|
end
|
@@ -2,6 +2,7 @@ require "test_helper"
|
|
2
2
|
|
3
3
|
class FormForTestTest < MiniTest::Spec
|
4
4
|
include Cell::Testing
|
5
|
+
controller SongsController # provides #url_options.
|
5
6
|
|
6
7
|
it do
|
7
8
|
cell("formtastic").().gsub(/\s\s/, "").must_equal %{<form novalidate=\"novalidate\" class=\"formtastic song\" id=\"edit_song_1\" action=\"/songs/1\" accept-charset=\"UTF-8\" method=\"post\"><input name=\"utf8\" type=\"hidden\" value=\"✓\" /><input type=\"hidden\" name=\"_method\" value=\"patch\" /> First <li class=\"string input required stringish\" id=\"song_id_input\"><label for=\"song_id\" class=\"label\">Id<abbr title=\"required\">*</abbr></label><input id=\"song_id\" type=\"text\" value=\"1\" name=\"song[id]\" /></li><li class=\"string input required stringish\" id=\"song_artist_id_input\"><label for=\"song_artist_id\" class=\"label\">Id<abbr title=\"required\">*</abbr></label><input id=\"song_artist_id\" type=\"text\" name=\"song[artist][id]\" /></li><fieldset class=\"actions\"><ol> <input type=\"submit\" name=\"commit\" value=\"Go!\" as=\"button\" class=\"btn btn-primary\" />
|
@@ -2,6 +2,7 @@ require "test_helper"
|
|
2
2
|
|
3
3
|
class SimpleFormTest < MiniTest::Spec
|
4
4
|
include Cell::Testing
|
5
|
+
controller SongsController # provides #url_options.
|
5
6
|
|
6
7
|
it do
|
7
8
|
cell("simple_form").().gsub(/\s\s/, "").must_equal %{<form class=\"simple_form edit_song\" id=\"edit_song_1\" action=\"/songs/1\" accept-charset=\"UTF-8\" method=\"post\"><input name=\"utf8\" type=\"hidden\" value=\"✓\" /><input type=\"hidden\" name=\"_method\" value=\"patch\" /> First <div class=\"input string required song_id\"><label class=\"string required\" for=\"song_id\"><abbr title=\"required\">*</abbr> Id</label><input class=\"string required\" required=\"required\" aria-required=\"true\" type=\"text\" value=\"1\" name=\"song[id]\" id=\"song_id\" /></div><div class=\"input string required song_artist_id\"><label class=\"string required\" for=\"song_artist_id\"><abbr title=\"required\">*</abbr> Id</label><input class=\"string required\" required=\"required\" aria-required=\"true\" type=\"text\" name=\"song[artist][id]\" id=\"song_artist_id\" /></div>
|
@@ -11,15 +11,26 @@ class UrlHelperTest < MiniTest::Spec
|
|
11
11
|
def show
|
12
12
|
url_for(model)
|
13
13
|
end
|
14
|
-
|
15
|
-
def default_url_options
|
16
|
-
{host: "rails.sucks"}
|
17
|
-
end
|
18
14
|
end
|
19
15
|
|
20
16
|
let (:song_cell) { Cell.new(Song.new, controller: controller) }
|
21
17
|
|
22
18
|
# path helpers work in cell instance.
|
23
19
|
it { song_cell.songs_path.must_equal "/songs" }
|
24
|
-
it { song_cell.().must_equal "http://
|
20
|
+
it { song_cell.().must_equal "http://test.host/songs/1" }
|
25
21
|
end
|
22
|
+
|
23
|
+
|
24
|
+
class UrlTest < ActionDispatch::IntegrationTest
|
25
|
+
include ::Capybara::DSL
|
26
|
+
|
27
|
+
it do
|
28
|
+
visit "/songs/new" # cell.url_for(Song.new)
|
29
|
+
page.text.must_equal "http://www.example.com/songs/1"
|
30
|
+
end
|
31
|
+
|
32
|
+
# it do
|
33
|
+
# visit "/songs/1/edit"
|
34
|
+
# page.text.must_equal "http://www.example.com/songs/1"
|
35
|
+
# end
|
36
|
+
end
|