cells 3.8.8 → 3.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -1
  3. data/.travis.yml +5 -2
  4. data/CHANGES.textile +23 -15
  5. data/Gemfile +1 -1
  6. data/README.md +412 -0
  7. data/Rakefile +2 -2
  8. data/cells.gemspec +5 -6
  9. data/gemfiles/Gemfile.rails3-0 +2 -2
  10. data/gemfiles/Gemfile.rails3-1 +1 -1
  11. data/gemfiles/Gemfile.rails3-2 +1 -2
  12. data/gemfiles/Gemfile.rails4-0 +7 -0
  13. data/lib/cell.rb +27 -0
  14. data/lib/cell/base.rb +31 -18
  15. data/lib/cell/builder.rb +11 -10
  16. data/lib/cell/dsl.rb +7 -0
  17. data/lib/cell/rack.rb +5 -9
  18. data/lib/cell/rails.rb +19 -11
  19. data/lib/cell/rails/view_model.rb +115 -0
  20. data/lib/cell/rails3_0_strategy.rb +1 -1
  21. data/lib/cell/rails3_1_strategy.rb +1 -1
  22. data/lib/cell/rails4_0_strategy.rb +1 -2
  23. data/lib/cell/test_case.rb +11 -11
  24. data/lib/cells.rb +4 -3
  25. data/lib/cells/rails.rb +16 -3
  26. data/lib/cells/version.rb +1 -1
  27. data/test/app/cells/bassist_cell.rb +9 -1
  28. data/test/app/cells/rails_helper_api_test/bassist/edit.html.erb +3 -3
  29. data/test/app/cells/song/dashboard.haml +7 -0
  30. data/test/app/cells/song/details.html.haml +1 -0
  31. data/test/app/cells/song/info.html.haml +1 -0
  32. data/test/app/cells/song/lyrics.html.haml +6 -0
  33. data/test/app/cells/song/plays.haml +1 -0
  34. data/test/app/cells/song/show.html.haml +3 -0
  35. data/test/app/cells/song/title.html.haml +1 -0
  36. data/test/app/cells/view_model_test/comments/show.haml +7 -0
  37. data/test/cell_module_test.rb +39 -41
  38. data/test/cell_test.rb +28 -0
  39. data/test/dummy/app/views/musician/featured_with_block.html.erb +1 -1
  40. data/test/dummy/app/views/musician/title.erb +1 -0
  41. data/test/dummy/config/routes.rb +1 -0
  42. data/test/helper_test.rb +13 -10
  43. data/test/rails/caching_test.rb +75 -73
  44. data/test/rails/cells_test.rb +25 -23
  45. data/test/rails/integration_test.rb +80 -61
  46. data/test/rails/view_model_test.rb +119 -0
  47. data/test/rails_helper_api_test.rb +11 -13
  48. metadata +41 -61
  49. data/README.rdoc +0 -279
  50. data/about.yml +0 -7
  51. data/test/app/cells/producer/capture.html.erb +0 -1
  52. data/test/app/cells/producer/content_for.html.erb +0 -2
  53. data/test/rails/capture_test.rb +0 -70
data/Rakefile CHANGED
@@ -3,11 +3,11 @@ Bundler::GemHelper.install_tasks
3
3
 
4
4
  require 'rake/testtask'
5
5
 
6
- desc 'Test the cells gem.'
6
+ desc 'Default: run unit tests.'
7
7
  task :default => :test
8
8
 
9
9
  Rake::TestTask.new(:test) do |test|
10
10
  test.libs << 'test'
11
- test.test_files = FileList['test/*_test.rb', 'test/rails/*_test.rb'] - ['test/rails/capture_test.rb']
11
+ test.test_files = FileList['test/*_test.rb', 'test/rails/*_test.rb']
12
12
  test.verbose = true
13
13
  end
data/cells.gemspec CHANGED
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  lib = File.expand_path('../lib/', __FILE__)
3
2
  $:.unshift lib unless $:.include?(lib)
4
3
 
@@ -13,19 +12,19 @@ Gem::Specification.new do |s|
13
12
  s.homepage = "http://cells.rubyforge.org"
14
13
  s.summary = %q{View Components for Rails.}
15
14
  s.description = %q{Cells are view components for Rails. They are lightweight controllers, can be rendered in views and thus provide an elegant and fast way for encapsulation and component-orientation.}
16
-
15
+ s.license = 'MIT'
16
+
17
17
  s.files = `git ls-files`.split("\n")
18
18
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
19
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
20
  s.require_paths = ["lib"]
21
-
21
+
22
22
  s.add_dependency "actionpack", ">= 3.0"
23
23
  s.add_dependency "railties", ">= 3.0"
24
-
24
+
25
25
  s.add_development_dependency "rake"
26
26
  s.add_development_dependency "haml"
27
27
  s.add_development_dependency "slim"
28
- s.add_development_dependency "simple_form"
29
28
  s.add_development_dependency "tzinfo" # FIXME: why the hell do we need this for 3.1?
30
- s.add_development_dependency "minitest", ">= 2.8.1"
29
+ s.add_development_dependency "minitest", "~> 4.7.5"
31
30
  end
@@ -1,6 +1,6 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- # Specify your gem's dependencies in roar-rails.gemspec
3
+ # Specify your gem's dependencies in cells.gemspec
4
4
  gemspec path: '../'
5
5
 
6
- gem 'railties', '~> 3.0.11'
6
+ gem 'railties', '3.0.20'
@@ -1,6 +1,6 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- # Specify your gem's dependencies in roar-rails.gemspec
3
+ # Specify your gem's dependencies in cells.gemspec
4
4
  gemspec path: '../'
5
5
 
6
6
  gem 'railties', '~> 3.1.0'
@@ -1,7 +1,6 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- # Specify your gem's dependencies in roar-rails.gemspec
3
+ # Specify your gem's dependencies in cells.gemspec
4
4
  gemspec path: '../'
5
5
 
6
6
  gem 'railties', '~> 3.2.0'
7
- gem 'haml', '~> 3.1.4'
@@ -0,0 +1,7 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in cells.gemspec
4
+ gemspec path: '../'
5
+
6
+ gem 'railties', '4.0.0'
7
+ gem 'activemodel'
data/lib/cell.rb ADDED
@@ -0,0 +1,27 @@
1
+ module Cell
2
+ module OptionsConstructor
3
+ private
4
+ def process_args(options={})
5
+ if options.is_a?(Hash) # TODO: i don't like this too much.
6
+ process_options(options)
7
+ else
8
+ process_model(options)
9
+ end
10
+
11
+ super # Base.
12
+ end
13
+
14
+ # DISCUSS: have 2 classes for that?
15
+
16
+ def process_options(options)
17
+ options.each do |k, v|
18
+ instance_variable_set("@#{k}", v)
19
+ singleton_class.class_eval { attr_reader k }
20
+ end
21
+ end
22
+
23
+ def process_model(model)
24
+ @model = model
25
+ end
26
+ end
27
+ end
data/lib/cell/base.rb CHANGED
@@ -2,40 +2,53 @@ require 'abstract_controller'
2
2
  require 'cell/builder'
3
3
  require 'cell/caching'
4
4
  require 'cell/rendering'
5
+ require 'cell/dsl'
5
6
 
6
7
  module Cell
7
8
  def self.rails3_0?
8
9
  ::ActionPack::VERSION::MAJOR == 3 and ::ActionPack::VERSION::MINOR == 0
9
10
  end
10
-
11
+
11
12
  def self.rails3_1_or_more?
12
- ::ActionPack::VERSION::MAJOR == 3 and ::ActionPack::VERSION::MINOR >= 1
13
+ (::ActionPack::VERSION::MAJOR == 3 and ::ActionPack::VERSION::MINOR >= 1) or ::ActionPack::VERSION::MAJOR > 3
13
14
  end
14
-
15
- def self.rails3_2_or_more? # FIXME: move to tests.
16
- ::ActionPack::VERSION::MAJOR == 3 and ::ActionPack::VERSION::MINOR >= 2
15
+
16
+ def self.rails3_2_or_more?
17
+ (::ActionPack::VERSION::MAJOR == 3 and ::ActionPack::VERSION::MINOR >= 2) or ::ActionPack::VERSION::MAJOR > 3
17
18
  end
18
19
 
19
- def self.rails4_0_or_more? # FIXME: move to tests.
20
- ::ActionPack::VERSION::MAJOR == 4
20
+ def self.rails4_0_or_more?
21
+ (::ActionPack::VERSION::MAJOR == 4 and ::ActionPack::VERSION::MINOR >= 0) or ::ActionPack::VERSION::MAJOR > 4
21
22
  end
22
-
23
-
23
+
24
+
24
25
  class Base < AbstractController::Base
26
+ # TODO: deprecate Base in favour of Cell.
27
+
25
28
  abstract!
26
29
  DEFAULT_VIEW_PATHS = [File.join('app', 'cells')]
27
-
30
+
28
31
  extend Builder
29
32
  include AbstractController
30
33
  include AbstractController::Rendering, Layouts, Helpers, Callbacks, Translation, Logger
31
-
34
+
32
35
  require 'cell/rails3_0_strategy' if Cell.rails3_0?
33
36
  require 'cell/rails3_1_strategy' if Cell.rails3_1_or_more?
34
37
  require 'cell/rails4_0_strategy' if Cell.rails4_0_or_more?
35
38
  include VersionStrategy
36
39
  include Rendering
37
40
  include Caching
38
-
41
+ include Cell::DSL
42
+
43
+ def initialize(*args)
44
+ super() # AbC::Base.
45
+ process_args(*args)
46
+ end
47
+
48
+ private
49
+ def process_args(*)
50
+ end
51
+
39
52
  class View < ActionView::Base
40
53
  def self.prepare(modules)
41
54
  # TODO: remove for 4.0 if PR https://github.com/rails/rails/pull/6826 is merged.
@@ -43,27 +56,27 @@ module Cell
43
56
  include *modules.reverse
44
57
  end
45
58
  end
46
-
59
+
47
60
  def render(*args, &block)
48
61
  options = args.first.is_a?(::Hash) ? args.first : {} # this is copied from #render by intention.
49
-
62
+
50
63
  return controller.render(*args, &block) if options[:state] or options[:view]
51
64
  super
52
65
  end
53
66
  end
54
-
55
-
67
+
68
+
56
69
  def self.view_context_class
57
70
  @view_context_class ||= begin
58
71
  Cell::Base::View.prepare(helper_modules)
59
72
  end
60
73
  end
61
-
74
+
62
75
  # Called in Railtie at initialization time.
63
76
  def self.setup_view_paths!
64
77
  self.view_paths = self::DEFAULT_VIEW_PATHS
65
78
  end
66
-
79
+
67
80
  def self.controller_path
68
81
  @controller_path ||= name.sub(/Cell$/, '').underscore unless anonymous?
69
82
  end
data/lib/cell/builder.rb CHANGED
@@ -5,19 +5,20 @@ module Cell
5
5
  # class with Cell::Base.build - this might lead to a different cell being returned.
6
6
  def create_cell_for(name, *args)
7
7
  class_from_cell_name(name).build_for(*args)
8
- end
9
-
8
+ end # TODO: rename to #cell_for.
9
+ alias_method :cell_for, :create_cell_for
10
+
10
11
  def build_for(*args) # DISCUSS: remove?
11
12
  build_class_for(*args).
12
13
  create_cell(*args)
13
14
  end
14
-
15
+
15
16
  # Adds a builder to the cell class. Builders are used in #render_cell to find out the concrete
16
17
  # class for rendering. This is helpful if you frequently want to render subclasses according
17
18
  # to different circumstances (e.g. login situations) and you don't want to place these deciders in
18
19
  # your view code.
19
20
  #
20
- # Passes the opts hash from #render_cell into the block. The block is executed in controller context.
21
+ # Passes the opts hash from #render_cell into the block. The block is executed in controller context.
21
22
  # Multiple build blocks are ORed, if no builder matches the building cell is used.
22
23
  #
23
24
  # Example:
@@ -41,17 +42,17 @@ module Cell
41
42
  def build(&block)
42
43
  builders << block
43
44
  end
44
-
45
+
45
46
  # The cell class constant for +cell_name+.
46
47
  def class_from_cell_name(cell_name)
47
48
  "#{cell_name}_cell".classify.constantize
48
49
  end
49
-
50
+
50
51
  # Override this if you want to receive arguments right in the cell constructor.
51
52
  def create_cell(*args)
52
- new
53
+ new(*args)
53
54
  end
54
-
55
+
55
56
  private
56
57
  def build_class_for(*args)
57
58
  builders.each do |blk|
@@ -59,11 +60,11 @@ module Cell
59
60
  end
60
61
  self
61
62
  end
62
-
63
+
63
64
  def run_builder_block(block, *args)
64
65
  block.call(*args)
65
66
  end
66
-
67
+
67
68
  def builders
68
69
  @builders ||= []
69
70
  end
data/lib/cell/dsl.rb ADDED
@@ -0,0 +1,7 @@
1
+ module Cell
2
+ module DSL
3
+ def cell(*args)
4
+ Base.cell_for(*args)
5
+ end
6
+ end
7
+ end
data/lib/cell/rack.rb CHANGED
@@ -5,7 +5,7 @@ module Cell
5
5
  # in the cell. This is especially useful when using gems like devise with your cell, without the
6
6
  # entire Cell::Rails overhead.
7
7
  #
8
- # The only dependency these kinds of cells have is a rack-compatible request object.
8
+ # The only dependency these kinds of cells have is a Rack-compatible request object.
9
9
  #
10
10
  # Example:
11
11
  #
@@ -16,20 +16,16 @@ module Cell
16
16
  class Rack < Base
17
17
  attr_reader :request
18
18
  delegate :session, :params, :to => :request
19
-
19
+
20
20
  class << self
21
21
  # DISCUSS: i don't like these class methods. maybe a RenderingStrategy?
22
- def create_cell(request, *args) # defined in Builder.
23
- new(request)
24
- end
25
-
26
22
  def render_cell_state(cell, state, request, *args) # defined in Rendering.
27
23
  super(cell, state, *args)
28
24
  end
29
25
  end
30
-
31
- def initialize(request)
32
- super()
26
+
27
+ def initialize(request, *args)
28
+ super(*args)
33
29
  @request = request
34
30
  end
35
31
  end
data/lib/cell/rails.rb CHANGED
@@ -4,10 +4,10 @@ module Cell
4
4
  class Rails < Rack
5
5
  # When this file is included we can savely assume that a rails environment with caching, etc. is available.
6
6
  include ActionController::RequestForgeryProtection
7
-
7
+
8
8
  abstract!
9
9
  delegate :session, :params, :request, :config, :env, :url_options, :to => :parent_controller
10
-
10
+
11
11
  class << self
12
12
  def cache_store
13
13
  # FIXME: i'd love to have an initializer in the cells gem that _sets_ the cache_store attr instead of overriding here.
@@ -15,33 +15,41 @@ module Cell
15
15
  # DISCUSS: should this be in Cell::Rails::Caching ?
16
16
  ActionController::Base.cache_store
17
17
  end
18
-
18
+
19
19
  def expire_cache_key(key, *args) # FIXME: move to Rails.
20
20
  expire_cache_key_for(key, cache_store ,*args)
21
21
  end
22
-
22
+
23
23
  private
24
24
  # Run builder block in controller instance context.
25
25
  def run_builder_block(block, controller, *args)
26
26
  controller.instance_exec(*args, &block)
27
27
  end
28
28
  end
29
-
30
-
29
+
30
+
31
31
  attr_reader :parent_controller
32
32
  alias_method :controller, :parent_controller
33
-
34
- def initialize(parent_controller)
35
- super
33
+
34
+ def initialize(parent_controller, *args)
35
+ super(parent_controller, *args) # FIXME: huh?
36
36
  @parent_controller = parent_controller
37
37
  end
38
-
38
+
39
39
  def cache_configured?
40
40
  ActionController::Base.send(:cache_configured?) # DISCUSS: why is it private?
41
41
  end
42
-
42
+
43
43
  def cache_store
44
44
  self.class.cache_store # in Rails, we have a global cache store.
45
45
  end
46
+
47
+ module DSL
48
+ def cell(name, *args)
49
+ # TODO: this method should be an instance method everywhere.
50
+ Base.cell_for(name, parent_controller, *args)
51
+ end
52
+ end
53
+ include DSL
46
54
  end
47
55
  end
@@ -0,0 +1,115 @@
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
+ class Cell::Rails
7
+ module ViewModel
8
+ include Cell::OptionsConstructor
9
+ #include ActionView::Helpers::UrlHelper
10
+ include ActionView::Context # this includes CompiledTemplates, too.
11
+ # properties :title, :body
12
+ attr_reader :model
13
+
14
+ module ClassMethods
15
+ def property(name)
16
+ delegate name, :to => :model
17
+ end
18
+ end
19
+ extend ActiveSupport::Concern
20
+
21
+
22
+ def render(options={})
23
+ if options.is_a?(Hash)
24
+ options.reverse_merge!(:view => state_for_implicit_render)
25
+ else
26
+ options = {:view => options.to_s}
27
+ end
28
+
29
+ super
30
+ end
31
+
32
+ def call
33
+ render implicit_state
34
+ end
35
+
36
+ private
37
+ def view_context
38
+ self
39
+ end
40
+
41
+ def state_for_implicit_render()
42
+ caller[1].match(/`(\w+)/)[1]
43
+ end
44
+
45
+ def implicit_state
46
+ controller_path.split("/").last
47
+ end
48
+ end
49
+
50
+
51
+ # FIXME: this module is to fix a design flaw in Rails 4.0. the problem is that AV::UrlHelper mixes in the wrong #url_for.
52
+ # if we could mix in everything else from the helper except for the #url_for, it would be fine.
53
+ module LinkToHelper
54
+ include ActionView::Helpers::TagHelper
55
+
56
+ def link_to(name = nil, options = nil, html_options = nil, &block)
57
+ html_options, options, name = options, name, block if block_given?
58
+ options ||= {}
59
+
60
+ html_options = convert_options_to_data_attributes(options, html_options)
61
+
62
+ url = url_for(options)
63
+ html_options['href'] ||= url
64
+
65
+ content_tag(:a, name || url, html_options, &block)
66
+ end
67
+
68
+ def convert_options_to_data_attributes(options, html_options)
69
+ if html_options
70
+ html_options = html_options.stringify_keys
71
+ html_options['data-remote'] = 'true' if link_to_remote_options?(options) || link_to_remote_options?(html_options)
72
+
73
+ disable_with = html_options.delete("disable_with")
74
+ confirm = html_options.delete('confirm')
75
+ method = html_options.delete('method')
76
+
77
+ if confirm
78
+ message = ":confirm option is deprecated and will be removed from Rails 4.1. " \
79
+ "Use 'data: { confirm: \'Text\' }' instead."
80
+ ActiveSupport::Deprecation.warn message
81
+
82
+ html_options["data-confirm"] = confirm
83
+ end
84
+
85
+ add_method_to_attributes!(html_options, method) if method
86
+
87
+ if disable_with
88
+ message = ":disable_with option is deprecated and will be removed from Rails 4.1. " \
89
+ "Use 'data: { disable_with: \'Text\' }' instead."
90
+ ActiveSupport::Deprecation.warn message
91
+
92
+ html_options["data-disable-with"] = disable_with
93
+ end
94
+
95
+ html_options
96
+ else
97
+ link_to_remote_options?(options) ? {'data-remote' => 'true'} : {}
98
+ end
99
+ end
100
+
101
+ def link_to_remote_options?(options)
102
+ if options.is_a?(Hash)
103
+ options.delete('remote') || options.delete(:remote)
104
+ end
105
+ end
106
+ end
107
+
108
+ # FIXME: fix that in rails core.
109
+ if Cell.rails4_0_or_more?
110
+ include LinkToHelper
111
+ else
112
+ include ActionView::Helpers::UrlHelper
113
+ end
114
+
115
+ end