Skip to content

Commit

Permalink
Merge branch 'master' into no-actioncontroller
Browse files Browse the repository at this point in the history
Conflicts:
	CHANGES.md
	test/concept_test.rb
  • Loading branch information
apotonick committed May 31, 2015
2 parents 035fb1a + 075ce97 commit d68c134
Show file tree
Hide file tree
Showing 94 changed files with 989 additions and 122 deletions.
16 changes: 16 additions & 0 deletions CHANGES.md
Expand Up @@ -18,8 +18,24 @@

* When using HAML, we do not use any of HAML's helper hacks to "fix" ActionView and XSS. While you might not note this, it removes tons of code from our stack.


## 4.0.0.beta5

* Assets bundled in engine cells now work.
* Directory change: Assets like `.css`, `.coffee` and `.js`, no longer have their own `assets/` directory but live inside the views directory of a cell. It turned out that two directories `views/` and `assets/` was too noisy for most users. If you think you have a valid point for re-introducing it, email me, it is not hard to implement.
* When bundling your cell's assets into the asset pipeline, you have to specify the full name of your cell. The names will be constantized.

```ruby
config.cells.with_assets = ["song/cell", "user_cell"] #=> Song::Cell, UserCell
```

## 4.0.0.beta4

* Fixed a bug when rendering more than once with ERB, the output buffer was being reused.
* API change: ViewModel::_prefixes now returns the "fully qualified" pathes including the view paths, prepended to the prefixes. This allows multiple view paths and basically fixes cells in engines.
* The only public way to retrieve prefixes for a cell is `ViewModel::prefixes`. The result is cached.


## 4.0.0.beta3

* Introduce `Cell::Testing` for Rspec and MiniTest.
Expand Down
1 change: 1 addition & 0 deletions Gemfile
Expand Up @@ -3,5 +3,6 @@ source "https://rubygems.org"
gem "railties", "~> 4.2.0"
gem "activemodel", "~> 4.2.0"
gem "minitest", "~> 5.2"
gem "cells-erb", path: "../cells-erb"

gemspec
11 changes: 11 additions & 0 deletions Rakefile
Expand Up @@ -11,3 +11,14 @@ Rake::TestTask.new(:test) do |test|
test.pattern = 'test/*_test.rb'
test.verbose = true
end

# Rake::TestTask.new(:rails) do |test|
# test.libs << 'test/rails'
# test.test_files = FileList['test/rails4.2/*_test.rb']
# test.verbose = true
# end

# rails_task = Rake::Task["rails"]
# test_task = Rake::Task["test"]
# default_task.enhance { test_task.invoke }
# default_task.enhance { rails_task.invoke }
4 changes: 2 additions & 2 deletions lib/cell.rb
Expand Up @@ -16,8 +16,8 @@ def self.rails_version
end

class TemplateMissingError < RuntimeError
def initialize(base, prefixes, view, engine, formats)
super("Template missing: view: `#{view.to_s}.#{engine}` prefixes: #{prefixes.inspect} view_paths:#{base.inspect}")
def initialize(prefixes, view, engine, formats)
super("Template missing: view: `#{view.to_s}.#{engine}` prefixes: #{prefixes.inspect}")
end
end # Error
end
Expand Down
2 changes: 1 addition & 1 deletion lib/cell/partial.rb
Expand Up @@ -10,7 +10,7 @@ def process_options!(options)
view = parts.pop
view = "_#{view}"
view += ".#{options[:formats].first}" if options[:formats]
prefixes = [parts.join("/")]
prefixes = self.class.view_paths.collect { |path| parts.unshift(path).join("/") }

options.merge!(:view => view, :prefixes => prefixes)
end
Expand Down
15 changes: 10 additions & 5 deletions lib/cell/prefixes.rb
@@ -1,26 +1,31 @@
# TODO: merge into Rails core.
# TODO: cache _prefixes on class layer.
module Cell::Prefixes
extend ActiveSupport::Concern

def _prefixes
self.class._prefixes
self.class.prefixes
end

# You're free to override those methods in case you want to alter our view inheritance.
module ClassMethods
def prefixes
@prefixes ||= _prefixes
end

private
def _prefixes
return [] if abstract?
_local_prefixes + superclass._prefixes
_local_prefixes + superclass.prefixes
end

def _local_prefixes
[controller_path]
view_paths.collect { |path| "#{path}/#{controller_path}" }
end

# Instructs Cells to inherit views from a parent cell without having to inherit class code.
def inherit_views(parent)
define_method :_prefixes do
super() + parent._prefixes
super() + parent.prefixes
end
end
end
Expand Down
41 changes: 1 addition & 40 deletions lib/cell/rails.rb
@@ -1,5 +1,4 @@
# These Methods are automatically added to all Controllers and Views when
# the cells plugin is loaded.
# These methods are automatically added to all controllers and views.
module Cell
module RailsExtensions
module ActionController
Expand All @@ -10,44 +9,6 @@ def cell(name, model=nil, options={}, &block)
def concept(name, model=nil, options={}, &block)
Concept.cell(name, model, options.merge(controller: self), &block)
end

# # Renders the cell state and returns the content. You may pass options here, too. They will be
# # around in @opts.
# #
# # Example:
# #
# # @box = render_cell(:posts, :latest, :user => current_user)
# #
# # If you need the cell instance before it renders, you can pass a block receiving the cell.
# #
# # Example:
# #
# # @box = render_cell(:comments, :top5) do |cell|
# # cell.markdown! if config.parse_comments?
# # end
# def render_cell(name, state, *args, &block)
# ::Cell::Rails.render_cell(name, state, self, *args, &block)
# end

# # Expires the cached cell state view, similar to ActionController::expire_fragment.
# # Usually, this method is used in Sweepers.
# # Beside the obvious first two args <tt>cell_name</tt> and <tt>state</tt> you can pass
# # in additional cache key <tt>args</tt> and cache store specific <tt>opts</tt>.
# #
# # Example:
# #
# # class ListSweeper < ActionController::Caching::Sweeper
# # observe List, Item
# #
# # def after_save(record)
# # expire_cell_state :my_listing, :display_list
# # end
# #
# # will expire the view for state <tt>:display_list</tt> in the cell <tt>MyListingCell</tt>.
# def expire_cell_state(cell_class, state, args={}, opts=nil)
# key = cell_class.state_cache_key(state, args)
# cell_class.expire_cache_key(key, opts)
# end
end

module ActionView
Expand Down
7 changes: 3 additions & 4 deletions lib/cell/railtie.rb
Expand Up @@ -19,10 +19,9 @@ class Railtie < Rails::Railtie

# ruthlessly stolen from the zurb-foundation gem.
initializer 'cells.update_asset_paths' do |app|
Array(app.config.cells.with_assets).each do |name|
# FIXME: this doesn't take engine cells into account.
app.config.assets.paths.append "#{app.root}/app/cells/#{name}/assets"
app.config.assets.paths.append "#{app.root}/app/concepts/#{name}/assets" # TODO: find out type.
Array(app.config.cells.with_assets).each do |cell_class|
# puts "@@@@@ #{cell_class.camelize.constantize.prefixes}"
app.config.assets.paths += cell_class.camelize.constantize.prefixes # Song::Cell.prefixes
end
end

Expand Down
20 changes: 9 additions & 11 deletions lib/cell/templates.rb
Expand Up @@ -2,10 +2,10 @@ module Cell
# Gets cached in production.
class Templates
# prefixes could be instance variable as they will never change.
def [](bases, prefixes, view, engine, formats=nil)
base = bases.first # FIXME.
def [](prefixes, view, engine, formats=nil)
view = "#{view}.#{engine}"

find_template(base, prefixes, view, engine)
find_template(prefixes, view, engine)
end

private
Expand All @@ -14,19 +14,17 @@ def cache
@cache ||= Cache.new
end

def find_template(base, prefixes, view, engine)
view = "#{view}.#{engine}"

def find_template(prefixes, view, engine)
cache.fetch(prefixes, view) do |prefix|
# this block is run once per cell class per process, for each prefix/view tuple.
create(base, prefix, view)
create(prefix, view)
end
end

def create(base, prefix, view)
# puts "...checking #{base}/#{prefix}/#{view}"
return unless File.exists?("#{base}/#{prefix}/#{view}") # DISCUSS: can we use Tilt.new here?
Tilt.new("#{base}/#{prefix}/#{view}", :escape_html => false, :escape_attrs => false)
def create(prefix, view)
# puts "...checking #{prefix}/#{view}"
return unless File.exists?("#{prefix}/#{view}") # DISCUSS: can we use Tilt.new here?
Tilt.new("#{prefix}/#{view}", escape_html: false, escape_attrs: false)
end

# {["comment/row/views", comment/views"][show.haml] => "Tpl:comment/view/show.haml"}
Expand Down
17 changes: 10 additions & 7 deletions lib/cell/testing.rb
Expand Up @@ -42,23 +42,26 @@ def call(*)


# Rails specific.
def controller
def controller_for(controller_class)
# TODO: test without controller.
return unless self.class.controller_class
return unless controller_class

# TODO: test with controller.
self.class.controller_class.new.tap do |ctl|
ctl.request = ActionController::TestRequest.new
ctl.instance_variable_set :@routes, Rails.application.routes.url_helpers
controller_class.new.tap do |ctl|
ctl.request = ::ActionController::TestRequest.new
ctl.instance_variable_set :@routes, ::Rails.application.routes.url_helpers
end
end

def controller # FIXME: this won't allow us using let(:controller) in MiniTest.
controller_for(self.class.controller_class)
end

def self.included(base)
base.class_eval do
extend Uber::InheritableAttr
inheritable_attr :controller_class

def self.controller(name)
def self.controller(name) # DSL method for the test.
self.controller_class = name
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/cell/version.rb
Expand Up @@ -3,7 +3,7 @@ module VERSION
MAJOR = 4
MINOR = 0
TINY = 0
PRE = "beta3"
PRE = "beta4"

STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
end
Expand Down
38 changes: 7 additions & 31 deletions lib/cell/view_model.rb
Expand Up @@ -25,7 +25,7 @@ def controller_path
extend Uber::Delegates

inheritable_attr :view_paths
self.view_paths = ["app/cells"] # DISCUSS: provide same API as rails?
self.view_paths = ["app/cells"]

inheritable_attr :template_engine
self.template_engine = "erb"
Expand Down Expand Up @@ -172,20 +172,20 @@ def to_s # output_buffer is returned at the end of the precompiled template.
end
end
def output_buffer # called from the precompiled template. FIXME: this is currently not used in Haml.
@output_buffer ||= OutputBuffer.new
OutputBuffer.new # don't cache output_buffer, for every render call we get a fresh one.
end
attr_writer :output_buffer # FIXME: where is that used? definitely not in Erbse.
# TODO: remove output_buffer in favor or returning the string.


module TemplateFor
def template_for(options)
view = options[:view]
engine = options[:template_engine]
base = options[:base]
prefixes = options[:prefixes]

# we could also pass _prefixes when creating class.templates, because prefixes are never gonna change per instance. not too sure if i'm just assuming this or if people need that.
self.class.templates[base, prefixes, view, engine] or raise TemplateMissingError.new(base, prefixes, view, engine, nil)
self.class.templates[prefixes, view, engine] or raise TemplateMissingError.new(prefixes, view, engine, nil)
end
end
include TemplateFor
Expand All @@ -199,13 +199,12 @@ def with_layout(options, content)

def normalize_options(options, caller) # TODO: rename to #setup_options! to be inline with Trb.
options = if options.is_a?(Hash)
options.reverse_merge(:view => state_for_implicit_render(caller)) # TODO: test implicit render!
options.reverse_merge(:view => state_for_implicit_render(caller))
else
{:view => options.to_s}
end

options[:template_engine] ||= self.class.template_engine # DISCUSS: in separate method?
options[:base] ||= self.class.view_paths
options[:prefixes] ||= _prefixes

process_options!(options)
Expand All @@ -228,31 +227,8 @@ def state_for_implicit_render(caller)


if defined?(ActionView)
# 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.
# if we could mix in everything else from the helper except for the #url_for, it would be fine.
# FIXME: fix that in rails core.
if Cell.rails_version <= Gem::Version.new('4.0')
include ActionView::Helpers::UrlHelper # gives us breaking #url_for.

def url_for(options = nil) # from ActionDispatch:R:UrlFor.
case options
when nil
_routes.url_for(url_options.symbolize_keys)
when Hash
_routes.url_for(options.symbolize_keys.reverse_merge!(url_options))
when String
options
when Array
polymorphic_url(options, options.extract_options!)
else
polymorphic_url(options)
end
end

public :url_for
else
include ActionView::Helpers::UrlHelper
end
# always include those helpers so we can override the shitty parts.
include ActionView::Helpers::UrlHelper
include ActionView::Helpers::FormTagHelper
end
end
Expand Down
6 changes: 3 additions & 3 deletions test/concept_test.rb
Expand Up @@ -40,9 +40,9 @@ class ConceptTest < MiniTest::Spec


describe "#_prefixes" do
it { Record::Cell.new._prefixes.must_equal ["record/views"] }
it { Record::Cell::Song.new._prefixes.must_equal ["record/song/views", "record/views"] }
it { Record::Cell::Hit.new._prefixes.must_equal ["record/hit/views", "record/views"] } # with inherit_views.
it { Record::Cell.new._prefixes.must_equal ["test/fixtures/concepts/record/views"] }
it { Record::Cell::Song.new._prefixes.must_equal ["test/fixtures/concepts/record/song/views", "test/fixtures/concepts/record/views"] }
it { Record::Cell::Hit.new._prefixes.must_equal ["test/fixtures/concepts/record/hit/views", "test/fixtures/concepts/record/views"] } # with inherit_views.
end

it { Record::Cell.new("Wayne").call(:show).must_equal "Party on, Wayne!" }
Expand Down
2 changes: 1 addition & 1 deletion test/dummy/config/application.rb
Expand Up @@ -21,7 +21,7 @@ class Application < Rails::Application
# enable asset pipeline as in development.
config.assets.enabled = true
config.assets.compile = true
config.cells.with_assets = ["album", "song"]
# config.cells.with_assets = ["song/cell"]
config.cache_classes = true

# Show full error reports and disable caching
Expand Down

0 comments on commit d68c134

Please sign in to comment.