cells 4.0.0.rc1 → 4.0.0

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.
@@ -29,6 +29,7 @@ require "cell/abstract"
29
29
  require "cell/util"
30
30
  require "cell/view_model"
31
31
  require "cell/concept"
32
+ require "cell/escaped"
32
33
 
33
34
 
34
35
  require "cell/railtie" if defined?(Rails)
@@ -1,19 +1,26 @@
1
- class Cell::Concept < Cell::ViewModel
2
- abstract!
3
- self.view_paths = ["app/concepts"]
1
+ module Cell
2
+ class Concept < Cell::ViewModel
3
+ abstract!
4
+ self.view_paths = ["app/concepts"]
4
5
 
5
- # TODO: this should be in Helper or something. this should be the only entry point from controller/view.
6
- class << self
7
- def class_from_cell_name(name)
8
- name.classify.constantize
9
- end
6
+ # TODO: this should be in Helper or something. this should be the only entry point from controller/view.
7
+ class << self
8
+ def class_from_cell_name(name)
9
+ name.classify.constantize
10
+ end
10
11
 
11
- def controller_path
12
- @controller_path ||= util.underscore(name.sub(/::Cell/, ''))
12
+ def controller_path
13
+ @controller_path ||= util.underscore(name.sub(/::Cell/, ''))
14
+ end
13
15
  end
14
- end
15
16
 
16
- alias_method :concept, :cell # the #cell helper to instantiate cells in cells.
17
+ alias_method :concept, :cell # Concept#concept does exactly what #cell does: delegate to class builder.
17
18
 
18
- self_contained!
19
+ # Get nested cell in instance.
20
+ def cell(name, model=nil, options={})
21
+ ViewModel.cell(name, model, options.merge(controller: parent_controller)) # #cell calls need to be delegated to ViewModel.
22
+ end
23
+
24
+ self_contained!
25
+ end
19
26
  end
@@ -0,0 +1,27 @@
1
+ module Cell::ViewModel::Escaped
2
+ def self.included(includer)
3
+ includer.extend Property
4
+ end
5
+
6
+ module Property
7
+ def property(name, *args)
8
+ super.tap do # super defines #title
9
+ mod = Module.new do
10
+ define_method(name) do |options={}|
11
+ value = super() # call the original #title.
12
+ return value unless value.is_a?(String)
13
+ return value if options[:escape] == false
14
+ escape!(value)
15
+ end
16
+ end
17
+ include mod
18
+ end
19
+ end
20
+ end # Property
21
+
22
+ # Can be used as a helper in the cell, too.
23
+ # Feel free to override and use a different escaping implementation.
24
+ def escape!(string)
25
+ ::ERB::Util.html_escape(string)
26
+ end
27
+ end
@@ -41,6 +41,10 @@ module Cell
41
41
  delegates :parent_controller, :session, :params, :request, :config, :env, :url_options
42
42
  end
43
43
 
44
+ def protect_against_forgery? # TODO: implement forgery protection with ActionController.
45
+ false
46
+ end
47
+
44
48
  def call(*)
45
49
  super.html_safe
46
50
  end
@@ -50,9 +50,9 @@ module Cell
50
50
  # TODO: allow to turn off this.
51
51
  initializer "cells.include_template_module", after: "cells.include_default_helpers" do
52
52
  # yepp, this is happening. saves me a lot of coding in each extension.
53
- ViewModel.send(:include, Cell::Erb) if Cell.const_defined?(:Erb)
54
- ViewModel.send(:include, Cell::Haml) if Cell.const_defined?(:Haml)
55
- ViewModel.send(:include, Cell::Slim) if Cell.const_defined?(:Slim)
53
+ ViewModel.send(:include, Cell::Erb) if Cell.const_defined?(:Erb, false)
54
+ ViewModel.send(:include, Cell::Haml) if Cell.const_defined?(:Haml, false)
55
+ ViewModel.send(:include, Cell::Slim) if Cell.const_defined?(:Slim, false)
56
56
  end
57
57
  # ViewModel.template_engine = app.config.app_generators.rails.fetch(:template_engine, 'erb').to_s
58
58
 
@@ -1,3 +1,3 @@
1
1
  module Cell
2
- VERSION = "4.0.0.rc1"
2
+ VERSION = "4.0.0"
3
3
  end
@@ -63,12 +63,19 @@ class ConceptTest < MiniTest::Spec
63
63
  it { Cell::Concept.cell("record/cell/song").show.must_equal "Lalala" }
64
64
  end
65
65
 
66
- describe "#cell (in cell state)" do
66
+
67
+ class RecordCell < Cell::ViewModel
68
+ def description
69
+ "Record! A Tribute To Rancid, with #{@options[:tracks]} songs! [#{parent_controller}]"
70
+ end
71
+ end
72
+
73
+ describe "#cell (in state)" do
67
74
  # test with controller, but remove tests when we don't need it anymore.
68
- it { Cell::Concept.cell("record/cell", nil, controller: Object).cell("record/cell", nil, tracks: 24).(:description).must_equal "A Tribute To Rancid, with 24 songs! [Object]" }
75
+ it { Cell::Concept.cell("record/cell", nil, controller: Object).cell("concept_test/record", nil, tracks: 24).(:description).must_equal "Record! A Tribute To Rancid, with 24 songs! [Object]" }
69
76
  it { Cell::Concept.cell("record/cell", nil, controller: Object).concept("record/cell", nil, tracks: 24).(:description).must_equal "A Tribute To Rancid, with 24 songs! [Object]" }
70
77
  # concept(.., collection: ..)
71
- it("xx") { Cell::Concept.cell("record/cell", nil, controller: Object).
78
+ it { Cell::Concept.cell("record/cell", nil, controller: Object).
72
79
  concept("record/cell", collection: [1,2], tracks: 24, method: :description).must_equal "A Tribute To Rancid, with 24 songs! [Object]A Tribute To Rancid, with 24 songs! [Object]" }
73
80
  end
74
81
  end
@@ -0,0 +1,41 @@
1
+ require "test_helper"
2
+
3
+ class PropertyTest < MiniTest::Spec
4
+ class SongCell < Cell::ViewModel
5
+ property :title
6
+
7
+ def title
8
+ super + "</b>"
9
+ end
10
+ end
11
+
12
+ let (:song) { Struct.new(:title).new("<b>She Sells And Sand Sandwiches") }
13
+ # ::property creates automatic accessor.
14
+ it { SongCell.(song).title.must_equal "<b>She Sells And Sand Sandwiches</b>" }
15
+ end
16
+
17
+
18
+ class EscapedPropertyTest < MiniTest::Spec
19
+ class SongCell < Cell::ViewModel
20
+ include Escaped
21
+ property :title
22
+ property :artist
23
+
24
+ def title(*)
25
+ "#{super}</b>" # super + "</b>" still escapes, but this is Rails.
26
+ end
27
+
28
+ def raw_title
29
+ title(escape: false)
30
+ end
31
+ end
32
+
33
+ let (:song) { Struct.new(:title, :artist).new("<b>She Sells And Sand Sandwiches", Object) }
34
+
35
+ # ::property escapes, everywhere.
36
+ it { SongCell.(song).title.must_equal "&lt;b&gt;She Sells And Sand Sandwiches</b>" }
37
+ # no escaping for non-strings.
38
+ it { SongCell.(song).artist.must_equal Object }
39
+ # no escaping when escape: false
40
+ it { SongCell.(song).raw_title.must_equal "<b>She Sells And Sand Sandwiches</b>" }
41
+ end
@@ -2,10 +2,6 @@ class FormForCell < Cell::ViewModel
2
2
  include ActionView::RecordIdentifier
3
3
  include ActionView::Helpers::FormHelper
4
4
 
5
- def protect_against_forgery?
6
- false
7
- end
8
-
9
5
  def show
10
6
  render
11
7
  end
@@ -3,10 +3,6 @@ class FormtasticCell < Cell::ViewModel
3
3
  include ActionView::Helpers::FormHelper
4
4
  include Formtastic::Helpers::FormHelper
5
5
 
6
- def protect_against_forgery?
7
- false
8
- end
9
-
10
6
  def show
11
7
  render
12
8
  end
@@ -6,10 +6,6 @@ class SimpleFormCell < Cell::ViewModel
6
6
  # include ActiveSupport::Configurable
7
7
  # include ActionController::RequestForgeryProtection # FIXME: this does NOT activate any protection.
8
8
 
9
- def protect_against_forgery?
10
- false
11
- end
12
-
13
9
  def show
14
10
  render
15
11
  end
@@ -0,0 +1 @@
1
+ <b><%= title %></b>
@@ -1,8 +1,14 @@
1
1
  class SongCell < Cell::ViewModel
2
+ include Escaped
3
+ property :title
4
+
2
5
  def show
3
6
  "happy"
4
7
  end
5
8
 
9
+ def with_escaped
10
+ render
11
+ end
6
12
  # include ActionView::Helpers::AssetUrlHelper
7
13
  # include Sprockets::Rails::Helper
8
14
 
@@ -14,4 +14,12 @@ class SongsController < ApplicationController
14
14
  def edit
15
15
  render text: cell(:song).video_path(1)
16
16
  end
17
+
18
+ def with_image_tag
19
+ render text: cell(:song).image_tag("logo.png")
20
+ end
21
+
22
+ def with_escaped
23
+ render layout: false
24
+ end
17
25
  end
@@ -1,4 +1,4 @@
1
- class Song
1
+ class Song < OpenStruct
2
2
  require "active_model"
3
3
  include ActiveModel::Conversion
4
4
  extend ActiveModel::Naming
@@ -0,0 +1 @@
1
+ <h1>Yeah!</h1><%= cell(:song, Song.new(title: "<script>")).(:with_escaped) %>
@@ -3,4 +3,7 @@ Rails.application.routes.draw do
3
3
  root to: "index#index"
4
4
 
5
5
  resources :songs
6
+
7
+ get "songs/with_image_tag"
8
+ get "songs/with_escaped"
6
9
  end
@@ -3,10 +3,14 @@ require "test_helper"
3
3
  class ControllerTest < ActionController::TestCase
4
4
  tests SongsController
5
5
 
6
- # TODO: test url stuff in Song#show.
7
6
  it do
8
7
  get :index
9
8
  response.body.must_equal "happy"
10
9
  end
11
10
 
11
+ # HTML escaping.
12
+ it do
13
+ get :with_escaped
14
+ response.body.must_equal "<h1>Yeah!</h1><b>&lt;script&gt;</b>" # only the property is escaped.
15
+ end
12
16
  end
@@ -33,4 +33,15 @@ class UrlTest < ActionDispatch::IntegrationTest
33
33
  # visit "/songs/1/edit"
34
34
  # page.text.must_equal "http://www.example.com/songs/1"
35
35
  # end
36
+
37
+
38
+ end
39
+
40
+ class AssetsHelperTest < ActionController::TestCase
41
+ tests SongsController
42
+
43
+ it do
44
+ get :with_image_tag
45
+ response.body.must_equal "<img src=\"/images/logo.png\" alt=\"Logo\" />"
46
+ end
36
47
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cells
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0.rc1
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Sutterer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-05 00:00:00.000000000 Z
11
+ date: 2015-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: uber
@@ -126,7 +126,7 @@ files:
126
126
  - lib/cell/caching/notification.rb
127
127
  - lib/cell/concept.rb
128
128
  - lib/cell/development.rb
129
- - lib/cell/engines.rb
129
+ - lib/cell/escaped.rb
130
130
  - lib/cell/layout.rb
131
131
  - lib/cell/partial.rb
132
132
  - lib/cell/prefixes.rb
@@ -210,6 +210,7 @@ files:
210
210
  - test/layout_test.rb
211
211
  - test/partial_test.rb
212
212
  - test/prefixes_test.rb
213
+ - test/property_test.rb
213
214
  - test/public_test.rb
214
215
  - test/rails4.2/.gitignore
215
216
  - test/rails4.2/Gemfile
@@ -224,6 +225,7 @@ files:
224
225
  - test/rails4.2/app/cells/simple_form/show.erb
225
226
  - test/rails4.2/app/cells/simple_form_cell.rb
226
227
  - test/rails4.2/app/cells/song/song.css
228
+ - test/rails4.2/app/cells/song/with_escaped.erb
227
229
  - test/rails4.2/app/cells/song_cell.rb
228
230
  - test/rails4.2/app/controllers/application_controller.rb
229
231
  - test/rails4.2/app/controllers/concerns/.keep
@@ -238,6 +240,7 @@ files:
238
240
  - test/rails4.2/app/views/index/index.html.erb
239
241
  - test/rails4.2/app/views/layouts/application.html.erb
240
242
  - test/rails4.2/app/views/songs/show.html.erb
243
+ - test/rails4.2/app/views/songs/with_escaped.html.erb
241
244
  - test/rails4.2/bin/bundle
242
245
  - test/rails4.2/bin/rails
243
246
  - test/rails4.2/bin/rake
@@ -289,11 +292,6 @@ files:
289
292
  - test/rails4.2/lib/assets/.keep
290
293
  - test/rails4.2/lib/tasks/.keep
291
294
  - test/rails4.2/log/.keep
292
- - test/rails4.2/public/404.html
293
- - test/rails4.2/public/422.html
294
- - test/rails4.2/public/500.html
295
- - test/rails4.2/public/favicon.ico
296
- - test/rails4.2/public/robots.txt
297
295
  - test/rails4.2/test/integration/asset_pipeline_test.rb
298
296
  - test/rails4.2/test/integration/controller_test.rb
299
297
  - test/rails4.2/test/integration/form_for_test.rb
@@ -323,9 +321,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
323
321
  version: '0'
324
322
  required_rubygems_version: !ruby/object:Gem::Requirement
325
323
  requirements:
326
- - - ">"
324
+ - - ">="
327
325
  - !ruby/object:Gem::Version
328
- version: 1.3.1
326
+ version: '0'
329
327
  requirements: []
330
328
  rubyforge_project:
331
329
  rubygems_version: 2.2.2
@@ -1,61 +0,0 @@
1
- module Cell
2
- # Now <tt>Rails::Engine</tt>s can contribute to Cells view paths.
3
- # By default, any 'app/cells' found inside any Engine is automatically included into Cells view paths.
4
- #
5
- # You can customize the view paths changing/appending to the <tt>'app/cell_views'</tt> path configuration:
6
- #
7
- # module MyAwesome
8
- # class Engine < Rails::Engine
9
- # # loads views from 'cell/views' and NOT from 'app/cells'
10
- # config.paths.add 'app/cell_views', :with => 'cell/views'
11
- #
12
- # # appends 'lib/my_cells_view_path' to this Railtie view path contribution
13
- # config.paths['app/cell_views'] << 'lib/my_cells_view_path'
14
- # end
15
- # end
16
- #
17
- # You can manually specify which Engines will be added to Cell view paths
18
- #
19
- # Cell::Base.config.view_path_engines = [MyAwesome::Engine]
20
- #
21
- # And even disable the automatic loading
22
- #
23
- # Cell::Base.config.view_path_engines = false
24
- #
25
- # You can programatically append a Rails::Engine to Cell view path
26
- #
27
- # Cells.setup do |config|
28
- # config.append_engine_view_path!(MyEngine::Engine)
29
- # end
30
- #
31
- module Engines
32
- extend VersionStrategy # adds #registered_engines and #existent_directories_for.
33
-
34
- # Appends all <tt>Rails::Engine</tt>s cell-views path to Cell::Base#view_paths
35
- #
36
- # All <tt>Rails::Engine</tt>s specified at <tt>config.view_path_engines</tt> will have its cell-views path appended to Cell::Base#view_paths
37
- #
38
- # Defaults <tt>config.view_path_engines</tt> to all loaded <tt>Rails::Engine</tt>s.
39
- #
40
- def self.append_engines_view_paths_for(config)
41
- return if config.view_path_engines == false
42
-
43
- engines = config.view_path_engines || registered_engines #::Rails::Application::Railties.engines
44
- engines.each {|engine| append_engine_view_path!(engine) }
45
- end
46
-
47
- # Appends a <tt>Rails::Engine</tt> cell-views path to @Cell::Base@
48
- #
49
- # The <tt>Rails::Engine</tt> cell-views path is obtained from the <tt>paths['app/cell_views']</tt> configuration.
50
- # All existing directories specified at cell-views path will be appended do Cell::Base#view_paths
51
- #
52
- # Defaults <tt>paths['app/cell_views']</tt> to 'app/cells'
53
- #
54
- def self.append_engine_view_path!(engine)
55
- return unless engine.is_a?(::Rails::Engine) # In Rails 4.1, this could be a Rails::Railtie, which doesn't make sense.
56
-
57
- engine.paths['app/cell_views'] || engine.paths.add('app/cell_views', :with => 'app/cells')
58
- Cell::Rails.append_view_path(existent_directories_for(engine.paths["app/cell_views"]))
59
- end
60
- end
61
- end
@@ -1,67 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>The page you were looking for doesn't exist (404)</title>
5
- <meta name="viewport" content="width=device-width,initial-scale=1">
6
- <style>
7
- body {
8
- background-color: #EFEFEF;
9
- color: #2E2F30;
10
- text-align: center;
11
- font-family: arial, sans-serif;
12
- margin: 0;
13
- }
14
-
15
- div.dialog {
16
- width: 95%;
17
- max-width: 33em;
18
- margin: 4em auto 0;
19
- }
20
-
21
- div.dialog > div {
22
- border: 1px solid #CCC;
23
- border-right-color: #999;
24
- border-left-color: #999;
25
- border-bottom-color: #BBB;
26
- border-top: #B00100 solid 4px;
27
- border-top-left-radius: 9px;
28
- border-top-right-radius: 9px;
29
- background-color: white;
30
- padding: 7px 12% 0;
31
- box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
- }
33
-
34
- h1 {
35
- font-size: 100%;
36
- color: #730E15;
37
- line-height: 1.5em;
38
- }
39
-
40
- div.dialog > p {
41
- margin: 0 0 1em;
42
- padding: 1em;
43
- background-color: #F7F7F7;
44
- border: 1px solid #CCC;
45
- border-right-color: #999;
46
- border-left-color: #999;
47
- border-bottom-color: #999;
48
- border-bottom-left-radius: 4px;
49
- border-bottom-right-radius: 4px;
50
- border-top-color: #DADADA;
51
- color: #666;
52
- box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
- }
54
- </style>
55
- </head>
56
-
57
- <body>
58
- <!-- This file lives in public/404.html -->
59
- <div class="dialog">
60
- <div>
61
- <h1>The page you were looking for doesn't exist.</h1>
62
- <p>You may have mistyped the address or the page may have moved.</p>
63
- </div>
64
- <p>If you are the application owner check the logs for more information.</p>
65
- </div>
66
- </body>
67
- </html>