view_driver 0.1.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.
- data/.gitignore +1 -0
- data/README.rdoc +138 -0
- data/Rakefile +29 -0
- data/VERSION +1 -0
- data/init.rb +1 -0
- data/lib/view_driver.rb +12 -0
- data/lib/view_driver/action_controller_extensions.rb +80 -0
- data/lib/view_driver/image_tag_extension.rb +12 -0
- data/lib/view_driver/normalized_section_template.rb +16 -0
- data/lib/view_driver/sections.rb +35 -0
- data/lib/view_driver/sections_collection.rb +49 -0
- data/lib/view_driver/view_helpers.rb +56 -0
- data/pkg/view_driver-0.1.0.gem +0 -0
- data/rails/init.rb +1 -0
- data/spec/sections_collection_spec.rb +122 -0
- data/spec/sections_spec.rb +40 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/view_driver_action_controller_extensions_spec.rb +94 -0
- data/spec/view_helpers_spec.rb +80 -0
- data/view_driver.gemspec +63 -0
- metadata +78 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
spec/debug.log
|
data/README.rdoc
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
view_driver helps to dry up views using sublayouts and sections.
|
2
|
+
|
3
|
+
== Sublayouts
|
4
|
+
|
5
|
+
Remember when you had to create one more layout which generally was almost the same as the default one for your application or your view templates contained duplicated html-markup.
|
6
|
+
|
7
|
+
This is what sublayouts are for.
|
8
|
+
|
9
|
+
=== How to use sublayouts
|
10
|
+
|
11
|
+
|
12
|
+
* Replace <%= yield %> or <%= @content_for_layout %> in your layout with <%= yield_with_sublayouts %>
|
13
|
+
* Put your sublayout into app/views/sublayouts
|
14
|
+
* Set the instance variable called @sublayout in the controller using 'sublayout' before_filter or manually
|
15
|
+
|
16
|
+
For example, if you've written something like
|
17
|
+
|
18
|
+
sublayout 'edit', :only => [:new, :create, :edit, :update]
|
19
|
+
|
20
|
+
in a controller and created a sublayout called app/views/sublayouts/edit.html.erb with <%= yield %> in it, the specified actions will be rendered within that sublayout.
|
21
|
+
|
22
|
+
The action's output will be inserted right in the layout if the sublayout has not been defined.
|
23
|
+
|
24
|
+
By default sublayouts live in app/views/sublayouts but you can pick any other folder e.g. 'layouts', creating an initializer with:
|
25
|
+
|
26
|
+
ViewDriver::SUBLAYOUTS_DIR = "layouts"
|
27
|
+
|
28
|
+
Sublayouts are quite suitable with sections.
|
29
|
+
|
30
|
+
== Sections
|
31
|
+
|
32
|
+
Sections are fragments of view similar to partials, which can be easily used in the application because they are well-structured and can be defined in the controller.
|
33
|
+
|
34
|
+
Imagine that in the layout there is a sidebar which can be the same or vary in different places. For example it can have no banner for one controller, or extra-blocks for another one. You can manage it with sections.
|
35
|
+
|
36
|
+
=== Naming and location
|
37
|
+
|
38
|
+
Default templates for a section are (by precedence):
|
39
|
+
|
40
|
+
1) for an action:
|
41
|
+
"app/views/#{@controller.controller_path}/#{@controller.action_name}_#{section_name}.html.erb"
|
42
|
+
2) for a controller:
|
43
|
+
"app/views/#{@controller.controller_path}/default_#{section_name}.html.erb"
|
44
|
+
3) for an application:
|
45
|
+
"app/views/sections/default_#{section_name}.html.erb"
|
46
|
+
|
47
|
+
You can change a default sections' location for an application defining ViewDriver::SECTIONS_DIR.
|
48
|
+
|
49
|
+
=== Rendering
|
50
|
+
|
51
|
+
For rendering there is a helper render_section, which can be put into your view file (it can be a layout, a sublayout or any other view file as well):
|
52
|
+
|
53
|
+
<%= render_section(:sidebar) %>
|
54
|
+
|
55
|
+
It will try to find the first template from the defaults above and render it, so if there is no default file for an action, it will take default for a controller and then for an application. If none of them are found it will render nothing.
|
56
|
+
|
57
|
+
==== Templates extensions
|
58
|
+
|
59
|
+
By default ViewDriver looks for templates with the "html.erb" extension. You can change this behaviour by defining ViewDriver::SECTIONS_TEMPLATES_EXTENSIONS, for example:
|
60
|
+
|
61
|
+
ViewDriver::SECTIONS_TEMPLATES_EXTENSIONS = ["haml"]
|
62
|
+
|
63
|
+
# be careful because it will require to check if a template exists for both extensions
|
64
|
+
ViewDriver::SECTIONS_TEMPLATES_EXTENSIONS = ["html.erb", "rhtml"]
|
65
|
+
|
66
|
+
ViewDriver caches templates' existence in production, check out ViewDriver::SectionsCollection#template_exists?
|
67
|
+
|
68
|
+
=== How to change templates for sections
|
69
|
+
|
70
|
+
You can do it by a 'sections' before_filter or manually (check out ViewDriver::ActionControllerExtensions::ClassMethods#sections for details).
|
71
|
+
|
72
|
+
Templates defined by the 'sections' before_filter is of higher precendence than the default ones.
|
73
|
+
|
74
|
+
Since the 'sections' is a before_filter it can be chained and controlled by standard options: :only, :except, :if, and :unless.
|
75
|
+
|
76
|
+
It will be easier to get it through the examples.
|
77
|
+
|
78
|
+
So let's assume that a controller for a current request is PagesController.
|
79
|
+
|
80
|
+
==== Default values for all sections
|
81
|
+
|
82
|
+
# sections will be taken first from :show action
|
83
|
+
sections 'show'
|
84
|
+
# so when you call render_section(:header) it will render 'pages/show_header' and if it doesn't exist it will look through the default chain
|
85
|
+
|
86
|
+
# if you pass the default value and the options hash, values will be merged
|
87
|
+
# so this will take all the sections from users folder except sidebar, which will be default
|
88
|
+
sections proc{|c| "users/#{c.action_name}"}, :sidebar => 'pages/default'
|
89
|
+
|
90
|
+
==== If you pass false as a template, it won't render section at all
|
91
|
+
|
92
|
+
# it won't render sections at all if a user is not logged in
|
93
|
+
sections false, :unless => proc{|c| c.logged_in?}
|
94
|
+
|
95
|
+
# it won't render sidebar section for the particular actions
|
96
|
+
sections :sidebar => false, :only => [:new, :edit, :update, :create]
|
97
|
+
|
98
|
+
==== Other examples
|
99
|
+
|
100
|
+
# :sidebar will be 'unlogged_sidebar' if a user is not logged in and 'logged_sidebar' otherwise
|
101
|
+
sections :sidebar => :sidebar_section
|
102
|
+
|
103
|
+
protected
|
104
|
+
def sidebar_section
|
105
|
+
logged_in? ? 'logged' : 'unlogged'
|
106
|
+
end
|
107
|
+
|
108
|
+
# the sections :sidebar and :navigations will be taken from the 'views/users' folder for :galleries and :users actions
|
109
|
+
sections :sidebar => 'users/show', :navigation => 'users/index', :only => [:galleries, :users]
|
110
|
+
|
111
|
+
# this sets all the sections to be default from 'users' folder for all requests passing the specified proc
|
112
|
+
sections 'users/default', :if => proc{|instance| !%w{static sessions}.include?(instance.controller_name)}
|
113
|
+
|
114
|
+
Besides strings sections before_filter accepts procs and methods (passed as symbols). Check out the sections method in the ActionControllerExtensions module.
|
115
|
+
|
116
|
+
== Add-ons
|
117
|
+
|
118
|
+
view_driver also comes with a helper method called 'classes' used to set css-classes or any other attributes conditionally.
|
119
|
+
|
120
|
+
<!-- will add 'logged' class if logged_in? method returns true -->
|
121
|
+
<%= content_tag(:div, 'test', :class => classes('default-class', ['logged', logged_in?])) %>
|
122
|
+
|
123
|
+
it also modifies image_tag a bit in order to use blank :alt attribute by default and duplicate it as :title attribute
|
124
|
+
|
125
|
+
>> image_tag 'quake.gif'
|
126
|
+
=> "<img alt='' src='/images/quake.gif' />"
|
127
|
+
>> image_tag 'quake.gif', :alt => 'foo'
|
128
|
+
=> "<img alt='foo' src='/images/quake.gif' title='foo' />"
|
129
|
+
>> image_tag 'quake.gif', :alt => 'foo', :title => 'bar'
|
130
|
+
=> "<img alt='foo' src='/images/quake.gif' title='bar' />"
|
131
|
+
|
132
|
+
== Installation
|
133
|
+
|
134
|
+
script/plugin install git://github.com/macovsky/view_driver.git
|
135
|
+
|
136
|
+
== Help
|
137
|
+
|
138
|
+
If you have any troubles using this plugin, you can ping me through robotector AT gmail.
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gemspec|
|
7
|
+
gemspec.name = "view_driver"
|
8
|
+
gemspec.summary = "Helps dry up Rails-views using sublayouts and sections"
|
9
|
+
gemspec.description = "Helps dry up Rails-views using sublayouts and sections"
|
10
|
+
gemspec.email = "robotector@gmail.com"
|
11
|
+
gemspec.homepage = "http://github.com/macovsky/view_driver"
|
12
|
+
gemspec.authors = ["Macovsky"]
|
13
|
+
end
|
14
|
+
Jeweler::GemcutterTasks.new
|
15
|
+
rescue LoadError
|
16
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
17
|
+
end
|
18
|
+
|
19
|
+
# require 'rake'
|
20
|
+
# require 'spec/rake/spectask'
|
21
|
+
#
|
22
|
+
# desc 'Default: run specs.'
|
23
|
+
# task :default => :spec
|
24
|
+
#
|
25
|
+
# desc 'Run the specs'
|
26
|
+
# Spec::Rake::SpecTask.new(:spec) do |t|
|
27
|
+
# t.spec_opts = ['--colour --format progress --loadby mtime --reverse']
|
28
|
+
# t.spec_files = FileList['spec/**/*_spec.rb']
|
29
|
+
# end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/rails/init.rb"
|
data/lib/view_driver.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
module ViewDriver
|
2
|
+
!defined?(SUBLAYOUTS_DIR) && SUBLAYOUTS_DIR = 'sublayouts'
|
3
|
+
!defined?(SECTIONS_DIR) && SECTIONS_DIR = 'sections'
|
4
|
+
!defined?(SECTIONS_TEMPLATES_EXTENSIONS) && SECTIONS_TEMPLATES_EXTENSIONS = ['html.erb']
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'view_driver/normalized_section_template'
|
8
|
+
require 'view_driver/sections'
|
9
|
+
require 'view_driver/sections_collection'
|
10
|
+
require 'view_driver/action_controller_extensions'
|
11
|
+
require 'view_driver/view_helpers'
|
12
|
+
require 'view_driver/image_tag_extension'
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module ViewDriver
|
2
|
+
module ActionControllerExtensions
|
3
|
+
FILTER_OPTIONS = [:only, :except, :if, :unless]
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
base.cattr_accessor :existing_sections
|
8
|
+
base.send :include, InstanceMethods
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
|
13
|
+
# Filter to define sections in a controller
|
14
|
+
def sections(*args)
|
15
|
+
method = "_sections_#{args.to_s.gsub(/[^a-z_]/, '_')}"
|
16
|
+
options = args.extract_options!
|
17
|
+
raise(ArgumentError, "Only one argument is allowed") if args.size > 1
|
18
|
+
|
19
|
+
before_filter method, options.slice(*FILTER_OPTIONS)
|
20
|
+
|
21
|
+
define_method method do
|
22
|
+
@sections_collection ||= SectionsCollection.new(self)
|
23
|
+
section_templates = options.except(*FILTER_OPTIONS)
|
24
|
+
section_templates.each{|k,v| section_templates[k] = parse_argument_for_sections(v)}
|
25
|
+
@sections_collection << Sections.new(parse_argument_for_sections(args.first), section_templates)
|
26
|
+
end
|
27
|
+
|
28
|
+
protected method.to_sym
|
29
|
+
end
|
30
|
+
|
31
|
+
# Filter to define a sublayout in a controller
|
32
|
+
def sublayout(*args)
|
33
|
+
method = "_sublayout_#{args.to_s.gsub(/[^a-z_]/, '_')}"
|
34
|
+
options = args.extract_options!
|
35
|
+
|
36
|
+
before_filter method, options.slice(*FILTER_OPTIONS)
|
37
|
+
|
38
|
+
define_method method do
|
39
|
+
@sublayout = case (sublayout = args.first)
|
40
|
+
when Symbol
|
41
|
+
send(sublayout)
|
42
|
+
when Proc
|
43
|
+
sublayout.call(self)
|
44
|
+
else
|
45
|
+
sublayout
|
46
|
+
end
|
47
|
+
end
|
48
|
+
protected method.to_sym
|
49
|
+
end
|
50
|
+
|
51
|
+
def default_section_templates(section, action_name)
|
52
|
+
[action_name, 'default'].map{|action| controller_path + "/#{action}_#{section}"} + [ViewDriver::SECTIONS_DIR + "/default_#{section}"]
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
module InstanceMethods
|
58
|
+
|
59
|
+
def default_section_templates(section, action = nil)
|
60
|
+
self.class.default_section_templates(section, action || action_name)
|
61
|
+
end
|
62
|
+
|
63
|
+
def parse_argument_for_sections(arg)
|
64
|
+
case arg
|
65
|
+
when Symbol
|
66
|
+
send(arg)
|
67
|
+
when Proc
|
68
|
+
arg.call(self)
|
69
|
+
when String, NilClass, FalseClass
|
70
|
+
arg
|
71
|
+
else
|
72
|
+
raise ArgumentError, "Unsupported argument"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
ActionController::Base.send(:include, ViewDriver::ActionControllerExtensions)
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module ActionView
|
2
|
+
module Helpers
|
3
|
+
module AssetTagHelper
|
4
|
+
def image_tag_with_title(source, options = {})
|
5
|
+
options[:alt] ||= ''
|
6
|
+
image_tag_without_title(source, options[:alt].blank? ? options : options.merge(:title => options[:title] || options[:alt]))
|
7
|
+
end
|
8
|
+
|
9
|
+
alias_method_chain :image_tag, :title
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ViewDriver
|
2
|
+
module ObjectExtensions
|
3
|
+
def normalized_section_template(section)
|
4
|
+
self
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
module StringExtensions
|
9
|
+
def normalized_section_template(section)
|
10
|
+
self !~ /_#{section}$/ ? self + "_#{section}" : self
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
Object.send :include, ViewDriver::ObjectExtensions
|
16
|
+
String.send :include, ViewDriver::StringExtensions
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module ViewDriver
|
2
|
+
class Sections
|
3
|
+
attr_reader :templates
|
4
|
+
|
5
|
+
def initialize(default_value, options = {})
|
6
|
+
@templates = convert_to_hash(default_value, options)
|
7
|
+
end
|
8
|
+
|
9
|
+
def template(section)
|
10
|
+
@templates[section].normalized_section_template(section)
|
11
|
+
end
|
12
|
+
|
13
|
+
def ==(sections)
|
14
|
+
@templates == sections.templates && @templates.default == sections.templates.default
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def convert_to_hash(default_value, options)
|
20
|
+
raise(ArgumentError, "No arguments were provided") if default_value.nil? && options.blank?
|
21
|
+
|
22
|
+
hash = case default_value
|
23
|
+
when Hash, HashWithIndifferentAccess
|
24
|
+
HashWithIndifferentAccess.new.merge(default_value)
|
25
|
+
when String, NilClass, FalseClass
|
26
|
+
HashWithIndifferentAccess.new(default_value)
|
27
|
+
else
|
28
|
+
raise(ArgumentError, 'Unsupported argument')
|
29
|
+
end
|
30
|
+
# using merge! because simple merge deletes default value
|
31
|
+
hash.merge!(options)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module ViewDriver
|
2
|
+
|
3
|
+
class SectionsCollection < Array
|
4
|
+
attr_reader :controller
|
5
|
+
|
6
|
+
def initialize(controller)
|
7
|
+
super()
|
8
|
+
@controller = controller
|
9
|
+
end
|
10
|
+
|
11
|
+
def templates(section)
|
12
|
+
defined_template = defined_template(section)
|
13
|
+
return [] if defined_template == false
|
14
|
+
([defined_template] + @controller.default_section_templates(section)).compact
|
15
|
+
end
|
16
|
+
|
17
|
+
def defined_template(section)
|
18
|
+
template = nil
|
19
|
+
each do |sections|
|
20
|
+
candidate = sections.template(section)
|
21
|
+
template = candidate unless candidate.nil?
|
22
|
+
end
|
23
|
+
prepend_controller_path(template)
|
24
|
+
end
|
25
|
+
|
26
|
+
def prepend_controller_path(template)
|
27
|
+
template.is_a?(String) && !template.include?("/") ? File.join(@controller.controller_path, template) : template
|
28
|
+
end
|
29
|
+
|
30
|
+
def template_to_render(section)
|
31
|
+
templates(section).find{|template| template_exists?(template)}
|
32
|
+
end
|
33
|
+
|
34
|
+
def template_exists?(template)
|
35
|
+
ViewDriver::SECTIONS_TEMPLATES_EXTENSIONS.any? do |ext|
|
36
|
+
basename = template + ".#{ext}"
|
37
|
+
file = File.join(RAILS_ROOT, 'app', 'views', basename)
|
38
|
+
unless @controller.perform_caching
|
39
|
+
File.exists?(file)
|
40
|
+
else
|
41
|
+
ApplicationController.existing_sections ||= {}
|
42
|
+
ApplicationController.existing_sections[basename].nil? && ApplicationController.existing_sections[basename] = File.exists?(file)
|
43
|
+
ApplicationController.existing_sections[basename]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module ViewDriver
|
2
|
+
module ViewHelpers
|
3
|
+
|
4
|
+
# Renders section :section for the current controller and action
|
5
|
+
def render_section(section)
|
6
|
+
@sections_collection ||= SectionsCollection.new(@controller)
|
7
|
+
|
8
|
+
if RAILS_ENV == "development"
|
9
|
+
_time1, _time2 = nil, nil
|
10
|
+
_time1 = Time.now
|
11
|
+
end
|
12
|
+
|
13
|
+
if template = @sections_collection.template_to_render(section)
|
14
|
+
result = render(:file => template)
|
15
|
+
if RAILS_ENV == "development"
|
16
|
+
_time2 = Time.now
|
17
|
+
logger.debug "Rendered section #{template} (#{((_time2 - _time1)*1000).round(1)}ms)"
|
18
|
+
end
|
19
|
+
result
|
20
|
+
elsif RAILS_ENV == "development"
|
21
|
+
logger.debug "Missing section #{section}"
|
22
|
+
"<!-- Missing section #{section} -->"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Renders sublayouts
|
27
|
+
# replace <%= yield %> or <%= @content_for_layout %> with it to use sublayouts
|
28
|
+
def yield_with_sublayouts
|
29
|
+
unless @sublayout.blank?
|
30
|
+
sublayout_file = @sublayout.include?('/') ? @sublayout : File.join(SUBLAYOUTS_DIR, @sublayout)
|
31
|
+
RAILS_ENV == 'development' && logger.debug("Rendering template within sublayout #{sublayout_file}")
|
32
|
+
render :file => sublayout_file
|
33
|
+
else
|
34
|
+
@content_for_layout
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# classes is to set css-classes or other attributes conditionally
|
39
|
+
# classes("class-without-conditions", ["logged-class", logged_in?], "third-class-without-conditions")
|
40
|
+
def classes(*pairs)
|
41
|
+
glued_classes = []
|
42
|
+
pairs.each do |pair|
|
43
|
+
next if pair.blank?
|
44
|
+
arr = Array(pair)
|
45
|
+
raise ArgumentError, "css_class or [css_class, condition] are expected (got #{pair.inspect})" if arr.size.zero? || arr.size > 2
|
46
|
+
glued_classes << arr[0] if arr[1] || arr.size == 1
|
47
|
+
end
|
48
|
+
glued_classes.any? ? glued_classes.join(" ") : nil
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
ActionView::Base.module_eval do
|
55
|
+
include ViewDriver::ViewHelpers
|
56
|
+
end
|
Binary file
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'view_driver'
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe ViewDriver::SectionsCollection do
|
4
|
+
include ViewDriverSpecHelper
|
5
|
+
|
6
|
+
before :each do
|
7
|
+
@controller = create_controller
|
8
|
+
@controller.action_name = 'show'
|
9
|
+
@collection = ViewDriver::SectionsCollection.new(@controller)
|
10
|
+
end
|
11
|
+
|
12
|
+
context "defined_template" do
|
13
|
+
it "should return nil when collection is blank" do
|
14
|
+
@collection.defined_template(:sidebar).should be_nil
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should return last value when only there was only one controller involved" do
|
18
|
+
@collection << ViewDriver::Sections.new('show', {})
|
19
|
+
@collection.defined_template(:sidebar).should == 'pages/show_sidebar'
|
20
|
+
end
|
21
|
+
|
22
|
+
context "with multiple sections" do
|
23
|
+
it "should return last not null value" do
|
24
|
+
@collection << ViewDriver::Sections.new('show', {})
|
25
|
+
@collection << ViewDriver::Sections.new(:sidebar => 'new')
|
26
|
+
@collection.defined_template(:sidebar).should == 'pages/new_sidebar'
|
27
|
+
@collection.defined_template(:subnavi).should == 'pages/show_subnavi'
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should return false value as last" do
|
31
|
+
@collection << ViewDriver::Sections.new(:sidebar => 'new')
|
32
|
+
@collection << ViewDriver::Sections.new(:sidebar => false)
|
33
|
+
@collection.defined_template(:sidebar).should be_false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "templates" do
|
39
|
+
it "should return empty collection if section is set to false" do
|
40
|
+
@collection << ViewDriver::Sections.new(false, {})
|
41
|
+
@collection.templates(:sidebar).should be_empty
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should return default templates if sections aren't set" do
|
45
|
+
@collection.templates(:sidebar).should == @controller.default_section_templates(:sidebar)
|
46
|
+
end
|
47
|
+
|
48
|
+
context "with defined sections" do
|
49
|
+
before :each do
|
50
|
+
@collection << ViewDriver::Sections.new(nil, {:sidebar => 'users/show'})
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should return a template defined by section + default templates for defined section" do
|
54
|
+
@collection.templates(:sidebar).should == ['users/show_sidebar'] + @collection.controller.default_section_templates(:sidebar)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should return default templates for undefined section" do
|
58
|
+
@collection.templates(:header).should == @controller.default_section_templates(:header)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "with multi defined sections" do
|
63
|
+
it "should return defined template + default templates" do
|
64
|
+
@collection << ViewDriver::Sections.new('create')
|
65
|
+
@collection << ViewDriver::Sections.new(nil, {:sidebar => 'new'})
|
66
|
+
|
67
|
+
@collection.templates(:header).should == ['pages/create_header'] + @controller.default_section_templates(:header)
|
68
|
+
@collection.templates(:sidebar).should == ['pages/new_sidebar'] + @controller.default_section_templates(:sidebar)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'template_to_render' do
|
74
|
+
it "should return first existing template" do
|
75
|
+
@collection << ViewDriver::Sections.new('create')
|
76
|
+
@collection.should_receive(:template_exists?).with('pages/create_sidebar').and_return(true)
|
77
|
+
@collection.template_to_render(:sidebar).should == 'pages/create_sidebar'
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should return nil if there weren't any templates" do
|
81
|
+
@collection.should_receive(:templates).with(:header).and_return([])
|
82
|
+
@collection.template_to_render(:header).should be_nil
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should return nil if there weren't any existing templates" do
|
86
|
+
@collection.should_receive(:template_exists?).exactly(3).and_return(false)
|
87
|
+
@collection.template_to_render(:sidebar).should be_nil
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'template_exists?' do
|
92
|
+
|
93
|
+
it "should ask File.exists? with possible template extensions" do
|
94
|
+
File.should_receive(:exists?).with(File.join(RAILS_ROOT, "app", "views", "pages/show_sidebar.html.erb")).and_return(true)
|
95
|
+
@collection.template_exists?("pages/show_sidebar").should be_true
|
96
|
+
end
|
97
|
+
|
98
|
+
context "with caching" do
|
99
|
+
before(:each) do
|
100
|
+
@controller.should_receive(:perform_caching).at_most(2).and_return(true)
|
101
|
+
end
|
102
|
+
|
103
|
+
after(:each) do
|
104
|
+
ApplicationController.existing_sections = nil
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should save the value" do
|
108
|
+
File.should_receive(:exists?).with(File.join(RAILS_ROOT, "app", "views", "pages/show_sidebar.html.erb")).and_return(true)
|
109
|
+
@collection.template_exists?("pages/show_sidebar").should be_true
|
110
|
+
ApplicationController.existing_sections.should == {"pages/show_sidebar.html.erb" => true}
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should not ask the file exist" do
|
114
|
+
ApplicationController.existing_sections = {"pages/show_sidebar.html.erb" => true}
|
115
|
+
@collection.template_exists?("pages/show_sidebar").should be_true
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe ViewDriver::Sections do
|
4
|
+
include ViewDriverSpecHelper
|
5
|
+
|
6
|
+
context "equality" do
|
7
|
+
before :each do
|
8
|
+
@sections = ViewDriver::Sections.new(nil, {:header => 'show'})
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should be equal to another object with the same templates" do
|
12
|
+
@sections.should == ViewDriver::Sections.new(nil, {:header => 'show'})
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should not be equal to objects with different templates" do
|
16
|
+
@sections.should_not == ViewDriver::Sections.new(false)
|
17
|
+
@sections.should_not == ViewDriver::Sections.new(false, {:header => 'show'})
|
18
|
+
@sections.should_not == ViewDriver::Sections.new(nil, {:header => 'temp'})
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'template' do
|
23
|
+
it "should return default value for unexisting section" do
|
24
|
+
ViewDriver::Sections.new(false).template(:header).should be_false
|
25
|
+
ViewDriver::Sections.new(false, {:header => 'users/show'}).template(:sidebar).should be_false
|
26
|
+
ViewDriver::Sections.new(nil, {:header => 'users/show'}).template(:sidebar).should be_nil
|
27
|
+
ViewDriver::Sections.new("show").template(:sidebar).should == "show_sidebar"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should add section's name" do
|
31
|
+
ViewDriver::Sections.new(nil, {:header => 'show'}).template(:header).should == "show_header"
|
32
|
+
ViewDriver::Sections.new(nil, {:header => 'users/show'}).template(:header).should == "users/show_header"
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should not add section's name" do
|
36
|
+
ViewDriver::Sections.new(nil, {:header => 'show_header'}).template(:header).should == 'show_header'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
begin
|
2
|
+
require File.dirname(__FILE__) + '/../../../../spec/spec_helper'
|
3
|
+
rescue LoadError
|
4
|
+
puts "You need to install rspec in your base app"
|
5
|
+
exit
|
6
|
+
end
|
7
|
+
|
8
|
+
plugin_spec_dir = File.dirname(__FILE__)
|
9
|
+
# ActiveRecord::Base.logger = Logger.new(plugin_spec_dir + "/debug.log")
|
10
|
+
|
11
|
+
module ViewDriverSpecHelper
|
12
|
+
def create_controller(controller_path = 'pages', super_class = ApplicationController, &block)
|
13
|
+
controller = Class.new(super_class)
|
14
|
+
|
15
|
+
controller.class_eval do
|
16
|
+
class_eval "def self.controller_path; '#{controller_path}'; end"
|
17
|
+
|
18
|
+
%w(index show new).each do |action|
|
19
|
+
class_eval <<-EOV, __FILE__, __LINE__
|
20
|
+
def #{action}
|
21
|
+
end
|
22
|
+
EOV
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
controller.class_eval(&block) if block
|
27
|
+
controller.new
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe ActionController do
|
4
|
+
include ViewDriverSpecHelper
|
5
|
+
|
6
|
+
context "default_section_templates" do
|
7
|
+
before :each do
|
8
|
+
@controller = create_controller
|
9
|
+
@controller.action_name = 'show'
|
10
|
+
@default_section_templates = ['pages/show_sidebar', 'pages/default_sidebar', "#{ViewDriver::SECTIONS_DIR}/default_sidebar"]
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should return default templates" do
|
14
|
+
@controller.default_section_templates(:sidebar).should == @default_section_templates
|
15
|
+
@controller.class.default_section_templates(:sidebar, 'show').should == @default_section_templates
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "sections" do
|
20
|
+
it "should define sections" do
|
21
|
+
@controller = create_controller do
|
22
|
+
sections :sidebar => 'show'
|
23
|
+
end
|
24
|
+
|
25
|
+
get 'index'
|
26
|
+
@controller.assigns["sections_collection"].should == (ViewDriver::SectionsCollection.new(@controller) << ViewDriver::Sections.new(nil, {:sidebar => 'show'}))
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should define multiple sections" do
|
30
|
+
@controller = create_controller('admin/pages') do
|
31
|
+
sections :sidebar => 'show'
|
32
|
+
sections :header => 'default'
|
33
|
+
end
|
34
|
+
|
35
|
+
get 'index'
|
36
|
+
@controller.assigns["sections_collection"].should == (ViewDriver::SectionsCollection.new(@controller) << ViewDriver::Sections.new(nil, {:sidebar => 'show'}) << ViewDriver::Sections.new(nil, {:header => 'default'}))
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should define sections using proc" do
|
40
|
+
@controller = create_controller do
|
41
|
+
sections proc{|c| "users/#{c.action_name}" }
|
42
|
+
end
|
43
|
+
|
44
|
+
get 'index'
|
45
|
+
@controller.assigns["sections_collection"].should == (ViewDriver::SectionsCollection.new(@controller) << ViewDriver::Sections.new('users/index'))
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should define sections using method" do
|
49
|
+
@controller = create_controller do
|
50
|
+
sections :change_sections
|
51
|
+
|
52
|
+
define_method 'change_sections' do
|
53
|
+
"users/#{action_name}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
get 'index'
|
58
|
+
@controller.assigns["sections_collection"].should == (ViewDriver::SectionsCollection.new(@controller) << ViewDriver::Sections.new('users/index'))
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "sublayout" do
|
63
|
+
it "should define sublayout" do
|
64
|
+
@controller = create_controller do
|
65
|
+
sublayout 'particular'
|
66
|
+
end
|
67
|
+
|
68
|
+
get 'index'
|
69
|
+
@controller.assigns["sublayout"].should == 'particular'
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should define sublayout using proc" do
|
73
|
+
@controller = create_controller do
|
74
|
+
sublayout proc{|c| "#{c.action_name}_particular"}
|
75
|
+
end
|
76
|
+
|
77
|
+
get 'index'
|
78
|
+
@controller.assigns["sublayout"].should == 'index_particular'
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should define sublayout using method" do
|
82
|
+
@controller = create_controller do
|
83
|
+
sublayout :change_sublayout
|
84
|
+
|
85
|
+
define_method 'change_sublayout' do
|
86
|
+
"#{action_name}_particular"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
get 'index'
|
91
|
+
@controller.assigns["sublayout"].should == 'index_particular'
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe ViewDriver::ViewHelpers do
|
4
|
+
include ViewDriver::ViewHelpers
|
5
|
+
include ViewDriverSpecHelper
|
6
|
+
|
7
|
+
context "render_section" do
|
8
|
+
before(:each) do
|
9
|
+
@controller = create_controller
|
10
|
+
@sections_collection = ViewDriver::SectionsCollection.new(@controller)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should return nil if no templates available" do
|
14
|
+
@sections_collection.should_receive(:template_to_render).with(:sidebar).and_return(nil)
|
15
|
+
render_section(:sidebar).should be_nil
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should return rendered template" do
|
19
|
+
@sections_collection.should_receive(:template_to_render).with(:sidebar).and_return('pages/default_sidebar')
|
20
|
+
should_receive(:render).with(:file => 'pages/default_sidebar').and_return('rendered pages/default_sidebar')
|
21
|
+
render_section(:sidebar).should == 'rendered pages/default_sidebar'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "yield_with_sublayouts" do
|
26
|
+
it "should return @content_for_layout if sublayout wasn't defined" do
|
27
|
+
yield_with_sublayouts.should be_nil
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should return rendered template" do
|
31
|
+
@sublayout = 'default'
|
32
|
+
should_receive(:render).with(:file => File.join(ViewDriver::SUBLAYOUTS_DIR, 'default')).and_return('rendered sublayout')
|
33
|
+
yield_with_sublayouts.should == 'rendered sublayout'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "classes" do
|
38
|
+
it "should return default classes" do
|
39
|
+
classes("default1", "default2").should == "default1 default2"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should return default classes and classes whose conditions were true" do
|
43
|
+
classes("default", ["one", true], ["two", false]).should == "default one"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should return nil if all the conditions were false" do
|
47
|
+
classes(["one", false], ["two", false]).should be_nil
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should return nil if nothing has been provided" do
|
51
|
+
classes.should be_nil
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should return nil if nil class has been provided" do
|
55
|
+
classes(nil).should be_nil
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should raise an error if more than 2 elements have been provided" do
|
59
|
+
lambda do
|
60
|
+
classes('class', ['1', '2', '3'])
|
61
|
+
end.should raise_error(ArgumentError)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "image_tag" do
|
66
|
+
it "should include empty alt tag" do
|
67
|
+
image_tag('i.gif').should include('alt=""')
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should duplicate alt's value to title" do
|
71
|
+
image_tag('i.gif', :alt => 'alt').should include('alt="alt"')
|
72
|
+
image_tag('i.gif', :alt => 'alt').should include('title="alt"')
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should set title's own value" do
|
76
|
+
image_tag('i.gif', :title => 'title').should include('alt=""')
|
77
|
+
image_tag('i.gif', :title => 'title').should include('title="title"')
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/view_driver.gemspec
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{view_driver}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Macovsky"]
|
12
|
+
s.date = %q{2009-12-07}
|
13
|
+
s.description = %q{Helps dry up Rails-views using sublayouts and sections}
|
14
|
+
s.email = %q{robotector@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.rdoc"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".gitignore",
|
20
|
+
"README.rdoc",
|
21
|
+
"Rakefile",
|
22
|
+
"VERSION",
|
23
|
+
"init.rb",
|
24
|
+
"lib/view_driver.rb",
|
25
|
+
"lib/view_driver/action_controller_extensions.rb",
|
26
|
+
"lib/view_driver/image_tag_extension.rb",
|
27
|
+
"lib/view_driver/normalized_section_template.rb",
|
28
|
+
"lib/view_driver/sections.rb",
|
29
|
+
"lib/view_driver/sections_collection.rb",
|
30
|
+
"lib/view_driver/view_helpers.rb",
|
31
|
+
"pkg/view_driver-0.1.0.gem",
|
32
|
+
"rails/init.rb",
|
33
|
+
"spec/sections_collection_spec.rb",
|
34
|
+
"spec/sections_spec.rb",
|
35
|
+
"spec/spec_helper.rb",
|
36
|
+
"spec/view_driver_action_controller_extensions_spec.rb",
|
37
|
+
"spec/view_helpers_spec.rb",
|
38
|
+
"view_driver.gemspec"
|
39
|
+
]
|
40
|
+
s.homepage = %q{http://github.com/macovsky/view_driver}
|
41
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
42
|
+
s.require_paths = ["lib"]
|
43
|
+
s.rubygems_version = %q{1.3.5}
|
44
|
+
s.summary = %q{Helps dry up Rails-views using sublayouts and sections}
|
45
|
+
s.test_files = [
|
46
|
+
"spec/sections_collection_spec.rb",
|
47
|
+
"spec/sections_spec.rb",
|
48
|
+
"spec/spec_helper.rb",
|
49
|
+
"spec/view_driver_action_controller_extensions_spec.rb",
|
50
|
+
"spec/view_helpers_spec.rb"
|
51
|
+
]
|
52
|
+
|
53
|
+
if s.respond_to? :specification_version then
|
54
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
55
|
+
s.specification_version = 3
|
56
|
+
|
57
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
58
|
+
else
|
59
|
+
end
|
60
|
+
else
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: view_driver
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Macovsky
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-07 00:00:00 +03:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Helps dry up Rails-views using sublayouts and sections
|
17
|
+
email: robotector@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
files:
|
25
|
+
- .gitignore
|
26
|
+
- README.rdoc
|
27
|
+
- Rakefile
|
28
|
+
- VERSION
|
29
|
+
- init.rb
|
30
|
+
- lib/view_driver.rb
|
31
|
+
- lib/view_driver/action_controller_extensions.rb
|
32
|
+
- lib/view_driver/image_tag_extension.rb
|
33
|
+
- lib/view_driver/normalized_section_template.rb
|
34
|
+
- lib/view_driver/sections.rb
|
35
|
+
- lib/view_driver/sections_collection.rb
|
36
|
+
- lib/view_driver/view_helpers.rb
|
37
|
+
- pkg/view_driver-0.1.0.gem
|
38
|
+
- rails/init.rb
|
39
|
+
- spec/sections_collection_spec.rb
|
40
|
+
- spec/sections_spec.rb
|
41
|
+
- spec/spec_helper.rb
|
42
|
+
- spec/view_driver_action_controller_extensions_spec.rb
|
43
|
+
- spec/view_helpers_spec.rb
|
44
|
+
- view_driver.gemspec
|
45
|
+
has_rdoc: true
|
46
|
+
homepage: http://github.com/macovsky/view_driver
|
47
|
+
licenses: []
|
48
|
+
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options:
|
51
|
+
- --charset=UTF-8
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: "0"
|
59
|
+
version:
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: "0"
|
65
|
+
version:
|
66
|
+
requirements: []
|
67
|
+
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 1.3.5
|
70
|
+
signing_key:
|
71
|
+
specification_version: 3
|
72
|
+
summary: Helps dry up Rails-views using sublayouts and sections
|
73
|
+
test_files:
|
74
|
+
- spec/sections_collection_spec.rb
|
75
|
+
- spec/sections_spec.rb
|
76
|
+
- spec/spec_helper.rb
|
77
|
+
- spec/view_driver_action_controller_extensions_spec.rb
|
78
|
+
- spec/view_helpers_spec.rb
|