view_driver 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|