liquidizer 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 +187 -0
- data/Rakefile +33 -0
- data/VERSION +1 -0
- data/app/models/liquid_template.rb +3 -0
- data/lib/liquidizer/controller_extensions.rb +219 -0
- data/lib/liquidizer/liquid_template.rb +23 -0
- data/lib/liquidizer/migration_extensions.rb +16 -0
- data/lib/liquidizer/support.rb +17 -0
- data/lib/liquidizer.rb +17 -0
- data/liquidizer.gemspec +67 -0
- data/rails/init.rb +1 -0
- data/test/controller_extensions_test.rb +244 -0
- data/test/fixtures/comments/index.html.erb +1 -0
- data/test/fixtures/posts/index.liquid +3 -0
- data/test/fixtures/ratings/_stuff.html.erb +1 -0
- data/test/fixtures/ratings/edit.html.erb +1 -0
- data/test/fixtures/spams/index.html.erb +1 -0
- data/test/liquid_template_test.rb +25 -0
- data/test/support_test.rb +24 -0
- data/test/test_helper.rb +24 -0
- metadata +100 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
pkg
|
data/README.rdoc
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
= Liquidizer
|
2
|
+
|
3
|
+
Liquidizer is a gem for Ruby on Rails that allows to render pages using templates stored in the
|
4
|
+
database. It uses liquid (http://www.liquidmarkup.org/) templating system (thus the name),
|
5
|
+
because it's easy to use, extend and it's safe to edit by users.
|
6
|
+
|
7
|
+
One example of when you might want to use it is this: Let's say you want to have a blogging
|
8
|
+
system where people can create their blogs about kittens, ninjas or vampires. Using this gem,
|
9
|
+
you can allow them to edit the look and feel of their blog using just their browser. Every
|
10
|
+
blog can have it's own set of templates.
|
11
|
+
|
12
|
+
|
13
|
+
== Installation
|
14
|
+
|
15
|
+
It's hosted on http://gemcutter.org. Add it to your source list if you don't have it already:
|
16
|
+
|
17
|
+
sudo gem source --add http://gemcutter.org
|
18
|
+
|
19
|
+
Then install:
|
20
|
+
|
21
|
+
sudo gem install liquidizer
|
22
|
+
|
23
|
+
And add this to your config/environment.rb:
|
24
|
+
|
25
|
+
config.gem 'liquidizer'
|
26
|
+
|
27
|
+
== How to use
|
28
|
+
|
29
|
+
First you have to specify which actions of which controllers should be liquified (rendered
|
30
|
+
with loadable liquid templates). To do that, use the +liquify+ controller macro:
|
31
|
+
|
32
|
+
class PostController < ApplicationController
|
33
|
+
# This will apply the templates to all actions in this controller.
|
34
|
+
liquify
|
35
|
+
end
|
36
|
+
|
37
|
+
If you want to liquify only some actions, but leave the others to be rendered using standard
|
38
|
+
Rails means, do this:
|
39
|
+
|
40
|
+
class PostController < ApplicationController
|
41
|
+
# Liquify only :show and :index.
|
42
|
+
liquify :show, :index
|
43
|
+
end
|
44
|
+
|
45
|
+
By default, Liquidizer will infer liquid template names from the controller and action name
|
46
|
+
in the same way Rails does. So action index in controller PostsController will have
|
47
|
+
template called "posts/index". Namespaced controllers work too: index in Blog::PostsController
|
48
|
+
will have template "blog/posts/index". This, however, can be overriden:
|
49
|
+
|
50
|
+
|
51
|
+
class PostController < ApplicationController
|
52
|
+
# This will liquify only show, but will use template called "awesome_show_template"
|
53
|
+
liquify :show, :as => 'awesome_show_template'
|
54
|
+
end
|
55
|
+
|
56
|
+
The +liquify+ macro is inherited, so if you want to apply liquid templates to all actions
|
57
|
+
in all controller, put it into ApplicationController. You can fine-tune it in derived
|
58
|
+
controllers, if you want:
|
59
|
+
|
60
|
+
class ApplicationController < ActionController::Base
|
61
|
+
liquify
|
62
|
+
end
|
63
|
+
|
64
|
+
class PostsController < ApplicationController
|
65
|
+
liquify :show, :as => 'kickass_show'
|
66
|
+
liquify :index, :as => 'hardcore_index'
|
67
|
+
end
|
68
|
+
|
69
|
+
To liquify also layouts, use the +liquify_layout+ macro:
|
70
|
+
|
71
|
+
class ApplicationController < ActionController::Base
|
72
|
+
# This will use layout called "layout"
|
73
|
+
liquify_layout
|
74
|
+
|
75
|
+
# This will use layout called "awesome_kickass_layout"
|
76
|
+
liquify_layout :as => "awesome_kickass_layout"
|
77
|
+
end
|
78
|
+
|
79
|
+
The last step is to tell Liquidizer where to load the liquid templates from. The way to implement
|
80
|
+
this is completely up to you. For example, you can associate the templates with the Blog model
|
81
|
+
(to follow the blog example) and have something like current_blog, which is loaded by the
|
82
|
+
current subdomain.
|
83
|
+
|
84
|
+
In any case, you need to provide a +current_liquid_templates+ method,
|
85
|
+
which should return collection of liquid templates to use. This method should return something
|
86
|
+
that responds at least to +find_by_name+ which returns an object that responds to +content+
|
87
|
+
which returns a string containing the liquid template.
|
88
|
+
|
89
|
+
The easies way to do this, is to have a +LiquidTemplate+ model and return a collections of
|
90
|
+
those in the +current_liquid_templates+. Liquidizer provides one such model for you,
|
91
|
+
but you will probably want to use your own. To make your life easier, there is a module
|
92
|
+
Liquidizer::LiquidTemplate which you can include into your template model to extend it with
|
93
|
+
some helpful methods (see the docs for more info):
|
94
|
+
|
95
|
+
class Blog < ActiveRecord::Base
|
96
|
+
has_many :liquid_templates
|
97
|
+
end
|
98
|
+
|
99
|
+
# The
|
100
|
+
class LiquidTemplate < ActiveRecord::Base
|
101
|
+
include Liquidizer::LiquidTemplate
|
102
|
+
belongs_to :blog
|
103
|
+
end
|
104
|
+
|
105
|
+
class ApplicationController < ActionController::Base
|
106
|
+
private
|
107
|
+
|
108
|
+
def current_liquid_templates
|
109
|
+
current_blog.liquid_templates
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
And that's it. You are now ready to kick asses!
|
114
|
+
|
115
|
+
== Instance variables
|
116
|
+
|
117
|
+
All instance variables that you assign in the controller are automatically available in the
|
118
|
+
liquid templates. The variable will be automatically wrapped in a "drop", if necessary
|
119
|
+
(please check the liquid docs for more details about what types can be passed directly to
|
120
|
+
liquid templates and what are drops). For a class +Foo+, a +FooDrop+ will be used if it
|
121
|
+
exists. If variable is not compatible with liquid and there is no corresponding drop class, it
|
122
|
+
won't be passed to the template.
|
123
|
+
|
124
|
+
Example:
|
125
|
+
|
126
|
+
A controller:
|
127
|
+
|
128
|
+
class PostsController < ActiveRecord::Base
|
129
|
+
liquify
|
130
|
+
|
131
|
+
def show
|
132
|
+
@post = current_blog.posts.find(params[:id])
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
A drop:
|
137
|
+
|
138
|
+
class PostDrop < Liquid::Drop
|
139
|
+
def initialize(post)
|
140
|
+
@post = post
|
141
|
+
end
|
142
|
+
|
143
|
+
def title
|
144
|
+
filter_nasty_stuff(@post.title)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
Then you can do this in your liquid template:
|
149
|
+
|
150
|
+
<h1>{{ post.title }}</h1>
|
151
|
+
|
152
|
+
<!-- more stuff ... -->
|
153
|
+
|
154
|
+
And the post.title will call PostDrop#title, filtering all nasty stuff.
|
155
|
+
|
156
|
+
The way how variables are wrapped with drops can be completelly customized by overriding the
|
157
|
+
+dropify+ method.
|
158
|
+
|
159
|
+
== Default templates
|
160
|
+
|
161
|
+
The Liquidizer::LiquidTemplate module gives your model capability to fallback to a default
|
162
|
+
template, if one is not found in the database. The default templates are stored in
|
163
|
+
db/liquid_templates. You can configure this location by setting the Liquidizer.template_path:
|
164
|
+
|
165
|
+
Liqduidizer.template_path = Rails.root.join('app', 'views', 'liquid_templates')
|
166
|
+
|
167
|
+
== TODO
|
168
|
+
|
169
|
+
There are several possible improvements to this gem:
|
170
|
+
|
171
|
+
- Extend it so it can handle different template systems in addition (unlikely, since I don't
|
172
|
+
need it and can't be bothered :) )
|
173
|
+
|
174
|
+
- The Rails 3 has improved ActionView API and as far as I understand, abstracts away the
|
175
|
+
concept of template storage. Taking advantage of this could potentialy simplify this gem.
|
176
|
+
Also, support Rails 3 in general would be nice.
|
177
|
+
|
178
|
+
- This does some nasty hacks into the ActionController::Base's render method. That method
|
179
|
+
originaly has quite liberal API, allowing to specify it's parameters in many ways. To make
|
180
|
+
this gem simple, some of those ways were sacrificed. Would be nice to support them too.
|
181
|
+
|
182
|
+
Potentialy many more. In any case, it's open source project (MIT), so no fear, fork me and
|
183
|
+
hack away!
|
184
|
+
|
185
|
+
== Legal stuff
|
186
|
+
|
187
|
+
Copyright (c) 2010 Adam Cigánek <adam.ciganek@gmail.com>. Released under the MIT License: www.opensource.org/licenses/mit-license.php
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
|
4
|
+
desc 'Default: run unit tests.'
|
5
|
+
task :default => :test
|
6
|
+
|
7
|
+
desc 'Run unit tests.'
|
8
|
+
Rake::TestTask.new(:test) do |t|
|
9
|
+
t.pattern = 'test/**/*_test.rb'
|
10
|
+
t.verbose = true
|
11
|
+
end
|
12
|
+
|
13
|
+
begin
|
14
|
+
require 'jeweler'
|
15
|
+
|
16
|
+
Jeweler::Tasks.new do |gemspec|
|
17
|
+
gemspec.name = 'liquidizer'
|
18
|
+
gemspec.summary = 'Support for Ruby on Rails views powered by Liquid and loaded from database'
|
19
|
+
gemspec.description = <<END
|
20
|
+
WIth this gem, you can render your Ruby on Rails views with liquid templates that are loaded from database. This way, the look and feel of your site can be safely configured by it's users.
|
21
|
+
END
|
22
|
+
|
23
|
+
gemspec.email = 'adam.ciganek@gmail.com'
|
24
|
+
gemspec.homepage = 'http://github.com/metatribe/liquidizer'
|
25
|
+
gemspec.authors = ['Adam Cigánek']
|
26
|
+
|
27
|
+
gemspec.add_dependency 'liquid', '>= 2.0.0'
|
28
|
+
end
|
29
|
+
|
30
|
+
Jeweler::GemcutterTasks.new
|
31
|
+
rescue LoadError
|
32
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
33
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,219 @@
|
|
1
|
+
require 'liquid'
|
2
|
+
require 'liquidizer/support'
|
3
|
+
|
4
|
+
module Liquidizer
|
5
|
+
module ControllerExtensions
|
6
|
+
def self.included(base)
|
7
|
+
base.class_eval do
|
8
|
+
extend ClassMethods
|
9
|
+
alias_method_chain :render, :liquid
|
10
|
+
|
11
|
+
class_inheritable_accessor :liquify_actions
|
12
|
+
class_inheritable_hash :liquid_template_names_for_actions
|
13
|
+
class_inheritable_accessor :liquid_template_name_for_layout
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def render_with_liquid(options = {}, &block)
|
18
|
+
if action_template = liquid_template_for_action(options)
|
19
|
+
assigns = assigns_for_liquify
|
20
|
+
content = action_template.render!(assigns)
|
21
|
+
|
22
|
+
if layout_template = liquid_template_for_layout(options)
|
23
|
+
content = layout_template.render!(assigns.merge('content_for_layout' => content))
|
24
|
+
options[:layout] = false
|
25
|
+
end
|
26
|
+
|
27
|
+
render_without_liquid(options.merge(:text => content))
|
28
|
+
else
|
29
|
+
if layout_template = liquid_template_for_layout(options)
|
30
|
+
assigns = assigns_for_liquify
|
31
|
+
|
32
|
+
content = render_to_string(options.merge(:layout => false))
|
33
|
+
content = layout_template.render!(assigns.merge('content_for_layout' => content))
|
34
|
+
|
35
|
+
render_without_liquid(options.merge(:text => content, :layout => false))
|
36
|
+
else
|
37
|
+
render_without_liquid(options, &block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def liquid_template_for_action(options)
|
45
|
+
action = extract_action_for_render(options)
|
46
|
+
|
47
|
+
if action && liquify?(action)
|
48
|
+
name = liquid_template_name_for_action(action)
|
49
|
+
find_and_parse_liquid_template(name)
|
50
|
+
else
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def liquify?(action)
|
56
|
+
self.class.liquify_actions == :all ||
|
57
|
+
self.class.liquify_actions &&
|
58
|
+
self.class.liquify_actions.include?(action.to_sym)
|
59
|
+
end
|
60
|
+
|
61
|
+
def liquid_template_for_layout(options)
|
62
|
+
if liquify_layout?(options)
|
63
|
+
find_and_parse_liquid_template(self.class.liquid_template_name_for_layout)
|
64
|
+
else
|
65
|
+
nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def liquify_layout?(options)
|
70
|
+
if options[:layout] == true ||
|
71
|
+
options[:layout].nil? && liquifiable_options?(options)
|
72
|
+
self.class.liquid_template_name_for_layout.present?
|
73
|
+
else
|
74
|
+
false
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def extract_action_for_render(options)
|
79
|
+
if options.nil?
|
80
|
+
action_name
|
81
|
+
elsif options[:action]
|
82
|
+
options[:action]
|
83
|
+
elsif liquifiable_options?(options)
|
84
|
+
action_name
|
85
|
+
else
|
86
|
+
nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
UNLIQUIFIABLE_OPTIONS = [:partial, :template, :file, :text, :xml, :json, :js, :inline]
|
91
|
+
|
92
|
+
def liquifiable_options?(options)
|
93
|
+
(options.keys.map(&:to_sym) & UNLIQUIFIABLE_OPTIONS).empty?
|
94
|
+
end
|
95
|
+
|
96
|
+
def find_and_parse_liquid_template(name)
|
97
|
+
if template_record = find_liquid_template(name)
|
98
|
+
template = Liquid::Template.parse(template_record.content)
|
99
|
+
prepare_liquid_template(template)
|
100
|
+
|
101
|
+
template
|
102
|
+
else
|
103
|
+
nil
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def liquid_template_name_for_action(action)
|
108
|
+
liquid_template_names_for_actions[action.to_sym] || infer_liquid_template_name(action)
|
109
|
+
end
|
110
|
+
|
111
|
+
def infer_liquid_template_name(action)
|
112
|
+
"#{controller_path}/#{action}"
|
113
|
+
end
|
114
|
+
|
115
|
+
def find_liquid_template(name)
|
116
|
+
current_liquid_templates.find_by_name(name)
|
117
|
+
end
|
118
|
+
|
119
|
+
# This can be overriden to do some nasty things to the template before it's rendered.
|
120
|
+
# For example, +assigns+ and +registers+ can be set here. The +template+ is an
|
121
|
+
# instance of Liquid::Template.
|
122
|
+
def prepare_liquid_template(template)
|
123
|
+
end
|
124
|
+
|
125
|
+
def assigns_for_liquify
|
126
|
+
variable_names = instance_variable_names
|
127
|
+
variable_names -= protected_instance_variables
|
128
|
+
|
129
|
+
variable_names.inject({}) do |memo, name|
|
130
|
+
assign_name = name[/^@(.*)$/, 1] # strip @
|
131
|
+
next memo if assign_name.starts_with?('_') # skip "private" ivars
|
132
|
+
|
133
|
+
value = instance_variable_get(name)
|
134
|
+
value = dropify(value) unless value.respond_to?(:to_liquid)
|
135
|
+
|
136
|
+
memo[assign_name] = value if value
|
137
|
+
memo
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Wrap the value in a drop, if it exists. Drop class is infered from the value class:
|
142
|
+
#
|
143
|
+
# Foo::Bar -> Foo::BarDrop
|
144
|
+
def dropify(value)
|
145
|
+
drop_class = infer_drop_class(value)
|
146
|
+
drop_class && drop_class.new(value)
|
147
|
+
end
|
148
|
+
|
149
|
+
def infer_drop_class(value)
|
150
|
+
name = value.class.name + 'Drop'
|
151
|
+
name = Liquidizer.drop_module.to_s + '::' + name if Liquidizer.drop_module
|
152
|
+
|
153
|
+
Support.constant_defined?(name) ? name.constantize : nil
|
154
|
+
end
|
155
|
+
|
156
|
+
module ClassMethods
|
157
|
+
# Define actions to liquify (render with liquid templates).
|
158
|
+
#
|
159
|
+
# == Examples
|
160
|
+
#
|
161
|
+
# # liquify all actions
|
162
|
+
# liquify
|
163
|
+
#
|
164
|
+
# # also liquify all actions
|
165
|
+
# liquify :all
|
166
|
+
#
|
167
|
+
# # liquify only show and index
|
168
|
+
# liquify :show, :index
|
169
|
+
#
|
170
|
+
# # liquify only edit, but use template called awesome_edit
|
171
|
+
# liquify :edit, :as => 'awesome_edit'
|
172
|
+
#
|
173
|
+
# Unless you specify template name with the :as options, the name will be
|
174
|
+
# inferend from controller and action names thusly:
|
175
|
+
#
|
176
|
+
# controller Blog, action :index - blogs/index
|
177
|
+
# controller Blog, action :show - blogs/show
|
178
|
+
# controller Blog, action :edit - blogs/edit
|
179
|
+
#
|
180
|
+
# controller Blog::Post, action :index - blog/posts/index
|
181
|
+
# controller Blog::Post, action :show - blog/posts/show
|
182
|
+
# controller Blog::Post, action :edit - blog/posts/edit
|
183
|
+
#
|
184
|
+
# You've got the idea.
|
185
|
+
#
|
186
|
+
def liquify(*actions)
|
187
|
+
options = actions.extract_options!
|
188
|
+
actions = actions.map(&:to_sym)
|
189
|
+
|
190
|
+
self.liquify_actions = actions.empty? ? :all : actions
|
191
|
+
self.liquid_template_names_for_actions = {}
|
192
|
+
|
193
|
+
if options[:as]
|
194
|
+
actions.each do |action|
|
195
|
+
self.liquid_template_names_for_actions[action] = options[:as]
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# Liquify the layout.
|
201
|
+
#
|
202
|
+
# == Examples
|
203
|
+
#
|
204
|
+
# # Uses layout template "layout"
|
205
|
+
# liquify_layout
|
206
|
+
#
|
207
|
+
# # Uses layout template "wicked_layout"
|
208
|
+
# liquify_layout :as => 'wicked_layout'
|
209
|
+
#
|
210
|
+
def liquify_layout(options = {})
|
211
|
+
self.liquid_template_name_for_layout = options[:as] || 'layout'
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
if defined?(ActionController::Base)
|
218
|
+
ActionController::Base.send(:include, Liquidizer::ControllerExtensions)
|
219
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Liquidizer
|
2
|
+
module LiquidTemplate
|
3
|
+
def self.included(base)
|
4
|
+
base.extend(ClassMethods)
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def find_by_name(name)
|
9
|
+
first(:conditions => {:name => name}) || load_default(name)
|
10
|
+
end
|
11
|
+
|
12
|
+
def load_default(name)
|
13
|
+
file_name = File.join(Liquidizer.template_path, name) + '.liquid'
|
14
|
+
|
15
|
+
if File.exist?(file_name)
|
16
|
+
new(:name => name, :content => File.read(file_name))
|
17
|
+
else
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Liquidizer
|
2
|
+
module MigrationExtensions
|
3
|
+
def create_liquid_templates_table
|
4
|
+
create_table :liquid_templates do |table|
|
5
|
+
table.string :name
|
6
|
+
table.text :content
|
7
|
+
end
|
8
|
+
|
9
|
+
add_index :liquid_templates, :name
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
if defined?(ActiveRecord::Migration)
|
15
|
+
ActiveRecord::Migration.extend(Liquidizer::MigrationExtensions)
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Liquidizer
|
2
|
+
module Support
|
3
|
+
# This is like Object.const_defined?, but works with namespaced constants (Foo::Bar::Baz).
|
4
|
+
def self.constant_defined?(name)
|
5
|
+
base = Object
|
6
|
+
name.split('::').each do |name|
|
7
|
+
if base.const_defined?(name)
|
8
|
+
base = base.const_get(name)
|
9
|
+
else
|
10
|
+
return false
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/liquidizer.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'liquidizer/controller_extensions'
|
2
|
+
require 'liquidizer/migration_extensions'
|
3
|
+
require 'liquidizer/liquid_template'
|
4
|
+
|
5
|
+
module Liquidizer
|
6
|
+
# The path the default liquid templates are stored.
|
7
|
+
mattr_accessor :template_path
|
8
|
+
|
9
|
+
# Module for drops. When instance variable is passed to a template, it's wrapped with a drop.
|
10
|
+
# This is a module the drops are looked up. If nil, the drops are looked up in the global
|
11
|
+
# namespace.
|
12
|
+
mattr_accessor :drop_module
|
13
|
+
|
14
|
+
if defined?(Rails)
|
15
|
+
self.template_path = "#{Rails.root}/db/liquid_templates"
|
16
|
+
end
|
17
|
+
end
|
data/liquidizer.gemspec
ADDED
@@ -0,0 +1,67 @@
|
|
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{liquidizer}
|
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 = ["Adam Cig\303\241nek"]
|
12
|
+
s.date = %q{2010-03-04}
|
13
|
+
s.description = %q{WIth this gem, you can render your Ruby on Rails views with liquid templates that are loaded from database. This way, the look and feel of your site can be safely configured by it's users.
|
14
|
+
}
|
15
|
+
s.email = %q{adam.ciganek@gmail.com}
|
16
|
+
s.extra_rdoc_files = [
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".gitignore",
|
21
|
+
"README.rdoc",
|
22
|
+
"Rakefile",
|
23
|
+
"VERSION",
|
24
|
+
"app/models/liquid_template.rb",
|
25
|
+
"lib/liquidizer.rb",
|
26
|
+
"lib/liquidizer/controller_extensions.rb",
|
27
|
+
"lib/liquidizer/liquid_template.rb",
|
28
|
+
"lib/liquidizer/migration_extensions.rb",
|
29
|
+
"lib/liquidizer/support.rb",
|
30
|
+
"liquidizer.gemspec",
|
31
|
+
"rails/init.rb",
|
32
|
+
"test/controller_extensions_test.rb",
|
33
|
+
"test/fixtures/comments/index.html.erb",
|
34
|
+
"test/fixtures/posts/index.liquid",
|
35
|
+
"test/fixtures/ratings/_stuff.html.erb",
|
36
|
+
"test/fixtures/ratings/edit.html.erb",
|
37
|
+
"test/fixtures/spams/index.html.erb",
|
38
|
+
"test/liquid_template_test.rb",
|
39
|
+
"test/support_test.rb",
|
40
|
+
"test/test_helper.rb"
|
41
|
+
]
|
42
|
+
s.homepage = %q{http://github.com/metatribe/liquidizer}
|
43
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
44
|
+
s.require_paths = ["lib"]
|
45
|
+
s.rubygems_version = %q{1.3.6}
|
46
|
+
s.summary = %q{Support for Ruby on Rails views powered by Liquid and loaded from database}
|
47
|
+
s.test_files = [
|
48
|
+
"test/support_test.rb",
|
49
|
+
"test/liquid_template_test.rb",
|
50
|
+
"test/controller_extensions_test.rb",
|
51
|
+
"test/test_helper.rb"
|
52
|
+
]
|
53
|
+
|
54
|
+
if s.respond_to? :specification_version then
|
55
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
56
|
+
s.specification_version = 3
|
57
|
+
|
58
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
59
|
+
s.add_runtime_dependency(%q<liquid>, [">= 2.0.0"])
|
60
|
+
else
|
61
|
+
s.add_dependency(%q<liquid>, [">= 2.0.0"])
|
62
|
+
end
|
63
|
+
else
|
64
|
+
s.add_dependency(%q<liquid>, [">= 2.0.0"])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'liquidizer'
|
@@ -0,0 +1,244 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class BaseController < ActionController::Base
|
4
|
+
append_view_path File.dirname(__FILE__) + '/fixtures'
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
def current_liquid_templates
|
9
|
+
LiquidTemplate
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class PostsController < BaseController
|
14
|
+
liquify
|
15
|
+
|
16
|
+
def index
|
17
|
+
@title = 'Hello blog!'
|
18
|
+
end
|
19
|
+
|
20
|
+
def show
|
21
|
+
@post = Post.new(:title => 'Liquidizer is awesome!')
|
22
|
+
end
|
23
|
+
|
24
|
+
def update
|
25
|
+
render :action => 'edit'
|
26
|
+
end
|
27
|
+
|
28
|
+
def create
|
29
|
+
render :status => :created
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class CommentsController < BaseController
|
34
|
+
liquify :show
|
35
|
+
liquify :edit, :as => 'funky_comments_edit'
|
36
|
+
|
37
|
+
def index
|
38
|
+
end
|
39
|
+
|
40
|
+
def show
|
41
|
+
end
|
42
|
+
|
43
|
+
def edit
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class RatingsController < BaseController
|
48
|
+
liquify :show
|
49
|
+
liquify_layout
|
50
|
+
|
51
|
+
def show
|
52
|
+
end
|
53
|
+
|
54
|
+
def edit
|
55
|
+
end
|
56
|
+
|
57
|
+
def new
|
58
|
+
render :partial => 'stuff'
|
59
|
+
end
|
60
|
+
|
61
|
+
def create
|
62
|
+
render :text => 'create'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class SpamsController < BaseController
|
67
|
+
def index
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class Post
|
72
|
+
def initialize(attributes = {})
|
73
|
+
self.title = attributes[:title]
|
74
|
+
end
|
75
|
+
|
76
|
+
attr_accessor :title
|
77
|
+
end
|
78
|
+
|
79
|
+
class PostDrop < Liquid::Drop
|
80
|
+
def initialize(post)
|
81
|
+
@post = post
|
82
|
+
end
|
83
|
+
|
84
|
+
def title
|
85
|
+
"<em>#{@post.title}</em>"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
module CoolDrops
|
90
|
+
class PostDrop < Liquid::Drop
|
91
|
+
def initialize(post)
|
92
|
+
@post = post
|
93
|
+
end
|
94
|
+
|
95
|
+
def title
|
96
|
+
"<strong>#{@post.title}</strong>"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class ControllerExtensionsTest < ActionController::TestCase
|
102
|
+
self.controller_class = nil
|
103
|
+
|
104
|
+
def setup
|
105
|
+
LiquidTemplate.destroy_all
|
106
|
+
end
|
107
|
+
|
108
|
+
def teardown
|
109
|
+
Liquidizer.drop_module = nil
|
110
|
+
end
|
111
|
+
|
112
|
+
test 'renders with liquid template' do
|
113
|
+
setup_controller(PostsController)
|
114
|
+
|
115
|
+
LiquidTemplate.create!(:name => 'posts/index', :content => "<p>This is liquid template</p>")
|
116
|
+
|
117
|
+
get :index
|
118
|
+
assert_select 'p', 'This is liquid template'
|
119
|
+
end
|
120
|
+
|
121
|
+
test 'passes instance variables to liquid template' do
|
122
|
+
setup_controller(PostsController)
|
123
|
+
|
124
|
+
LiquidTemplate.create!(:name => 'posts/index', :content => "<h1>{{ title }}</h1>")
|
125
|
+
|
126
|
+
get :index
|
127
|
+
assert_select 'h1', /Hello blog!/
|
128
|
+
end
|
129
|
+
|
130
|
+
test 'renders with liquid template when explicit action specified' do
|
131
|
+
setup_controller(PostsController)
|
132
|
+
|
133
|
+
LiquidTemplate.create!(:name => 'posts/edit', :content => "<p>edit post</p>")
|
134
|
+
LiquidTemplate.create!(:name => 'posts/update', :content => "<p>update post</p>")
|
135
|
+
|
136
|
+
get :update
|
137
|
+
assert_select 'p', 'edit post'
|
138
|
+
end
|
139
|
+
|
140
|
+
test 'preserves additional render options' do
|
141
|
+
setup_controller(PostsController)
|
142
|
+
|
143
|
+
LiquidTemplate.create!(:name => 'posts/create', :content => "<p>create post</p>")
|
144
|
+
|
145
|
+
get :create
|
146
|
+
assert_response :created
|
147
|
+
end
|
148
|
+
|
149
|
+
test 'does not render with liquid template actions that were not liquified' do
|
150
|
+
setup_controller(CommentsController)
|
151
|
+
|
152
|
+
get :index
|
153
|
+
assert_select 'h1', 'This is not liquid template'
|
154
|
+
end
|
155
|
+
|
156
|
+
test 'does not render with liquid if liquify macro not called at all' do
|
157
|
+
setup_controller(SpamsController)
|
158
|
+
|
159
|
+
get :index
|
160
|
+
assert_select 'h1', 'This is not liquid template'
|
161
|
+
end
|
162
|
+
|
163
|
+
test 'renders with liquid template with custom name' do
|
164
|
+
setup_controller(CommentsController)
|
165
|
+
|
166
|
+
LiquidTemplate.create!(:name => 'comments/edit', :content => "<p>default edit</p>")
|
167
|
+
LiquidTemplate.create!(:name => 'funky_comments_edit', :content => "<p>funky edit</p>")
|
168
|
+
|
169
|
+
get :edit
|
170
|
+
assert_select 'p', 'funky edit'
|
171
|
+
end
|
172
|
+
|
173
|
+
test 'renders liquid template with liquid layout' do
|
174
|
+
setup_controller(RatingsController)
|
175
|
+
|
176
|
+
LiquidTemplate.create!(:name => 'ratings/show', :content => '<p>This is liquid template</p>')
|
177
|
+
LiquidTemplate.create!(:name => 'layout',
|
178
|
+
:content => '<div id="layout">{{ content_for_layout }}</div>')
|
179
|
+
|
180
|
+
get :show
|
181
|
+
assert_select '#layout p', 'This is liquid template'
|
182
|
+
end
|
183
|
+
|
184
|
+
test 'renders solid template with liquid layout' do
|
185
|
+
setup_controller(RatingsController)
|
186
|
+
|
187
|
+
LiquidTemplate.create!(:name => 'layout',
|
188
|
+
:content => '<div id="layout">{{ content_for_layout }}</div>')
|
189
|
+
|
190
|
+
get :edit
|
191
|
+
assert_select '#layout p', 'This is not liquid template'
|
192
|
+
end
|
193
|
+
|
194
|
+
test 'does not apply liquid layout to render :partial' do
|
195
|
+
setup_controller(RatingsController)
|
196
|
+
|
197
|
+
LiquidTemplate.create!(:name => 'layout',
|
198
|
+
:content => '<div id="layout">{{ content_for_layout }}</div>')
|
199
|
+
|
200
|
+
get :new
|
201
|
+
assert_select '#layout', false
|
202
|
+
end
|
203
|
+
|
204
|
+
test 'does not apply liquid layout to render :text' do
|
205
|
+
setup_controller(RatingsController)
|
206
|
+
|
207
|
+
LiquidTemplate.create!(:name => 'layout',
|
208
|
+
:content => '<div id="layout">{{ content_for_layout }}</div>')
|
209
|
+
|
210
|
+
get :create
|
211
|
+
assert_select '#layout', false
|
212
|
+
end
|
213
|
+
|
214
|
+
test 'dropifies instance variables' do
|
215
|
+
setup_controller(PostsController)
|
216
|
+
|
217
|
+
LiquidTemplate.create!(:name => 'posts/show', :content => '<h1>{{ post.title }}</h1>')
|
218
|
+
|
219
|
+
get :show
|
220
|
+
assert_select 'h1 em', 'Liquidizer is awesome!'
|
221
|
+
end
|
222
|
+
|
223
|
+
test 'dropifies instance variables using namespaced drop' do
|
224
|
+
setup_controller(PostsController)
|
225
|
+
Liquidizer.drop_module = CoolDrops
|
226
|
+
|
227
|
+
LiquidTemplate.create!(:name => 'posts/show', :content => '<h1>{{ post.title }}</h1>')
|
228
|
+
|
229
|
+
get :show
|
230
|
+
assert_select 'h1 strong', 'Liquidizer is awesome!'
|
231
|
+
end
|
232
|
+
|
233
|
+
private
|
234
|
+
|
235
|
+
def setup_controller(controller_class)
|
236
|
+
self.class.prepare_controller_class(controller_class)
|
237
|
+
|
238
|
+
# This is copied over from ActionController::TestCase.setup_controller_request_and_response
|
239
|
+
@controller = controller_class.new
|
240
|
+
@controller.request = @request
|
241
|
+
@controller.params = {}
|
242
|
+
@controller.send(:initialize_current_url)
|
243
|
+
end
|
244
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<h1>This is not liquid template</h1>
|
@@ -0,0 +1 @@
|
|
1
|
+
Stuff
|
@@ -0,0 +1 @@
|
|
1
|
+
<p>This is not liquid template</p>
|
@@ -0,0 +1 @@
|
|
1
|
+
<h1>This is not liquid template</h1>
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class LiquidTemplateTest < ActiveSupport::TestCase
|
4
|
+
def setup
|
5
|
+
LiquidTemplate.delete_all
|
6
|
+
end
|
7
|
+
|
8
|
+
test 'find_by_name finds template by name if it exists' do
|
9
|
+
one = LiquidTemplate.create!(:name => 'posts/index')
|
10
|
+
two = LiquidTemplate.create!(:name => 'posts/show')
|
11
|
+
|
12
|
+
assert_equal one, LiquidTemplate.find_by_name('posts/index')
|
13
|
+
end
|
14
|
+
|
15
|
+
test 'find_by_name fallbacks to default template' do
|
16
|
+
expected_content = File.read(File.dirname(__FILE__) + '/fixtures/posts/index.liquid')
|
17
|
+
found = LiquidTemplate.find_by_name('posts/index')
|
18
|
+
|
19
|
+
assert_equal expected_content, found.content
|
20
|
+
end
|
21
|
+
|
22
|
+
test 'find_by_name returns nil if not even default template exists' do
|
23
|
+
assert_nil LiquidTemplate.find_by_name('ninjas!')
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
module Foo
|
4
|
+
class Bar
|
5
|
+
end
|
6
|
+
|
7
|
+
class Awesomeness
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Bar
|
12
|
+
end
|
13
|
+
|
14
|
+
class SupportTest < ActiveSupport::TestCase
|
15
|
+
test 'constant_defined? with non-namespaced constant' do
|
16
|
+
assert Liquidizer::Support.constant_defined?('Bar')
|
17
|
+
assert !Liquidizer::Support.constant_defined?('Baz')
|
18
|
+
end
|
19
|
+
|
20
|
+
test 'constant_defined? with namespaced constant' do
|
21
|
+
assert Liquidizer::Support.constant_defined?('Foo::Bar')
|
22
|
+
assert !Liquidizer::Support.constant_defined?('Foo::Baz')
|
23
|
+
end
|
24
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'action_controller'
|
4
|
+
require 'active_record'
|
5
|
+
require 'active_support/test_case'
|
6
|
+
|
7
|
+
$: << File.dirname(__FILE__) + '/../lib'
|
8
|
+
$: << File.dirname(__FILE__) + '/../app/models'
|
9
|
+
|
10
|
+
require 'liquidizer'
|
11
|
+
require 'liquid_template'
|
12
|
+
|
13
|
+
Liquidizer.template_path = File.dirname(__FILE__) + '/fixtures'
|
14
|
+
|
15
|
+
# Establish a temporary sqlite3 db for testing.
|
16
|
+
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
|
17
|
+
ActiveRecord::Base.logger # instantiate logger
|
18
|
+
ActiveRecord::Schema.define(:version => 1) do
|
19
|
+
create_liquid_templates_table
|
20
|
+
end
|
21
|
+
|
22
|
+
ActionController::Routing::Routes.draw do |map|
|
23
|
+
map.connect ':controller/:action/:id'
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: liquidizer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- "Adam Cig\xC3\xA1nek"
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-03-04 00:00:00 +01:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: liquid
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 2
|
29
|
+
- 0
|
30
|
+
- 0
|
31
|
+
version: 2.0.0
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
description: |
|
35
|
+
WIth this gem, you can render your Ruby on Rails views with liquid templates that are loaded from database. This way, the look and feel of your site can be safely configured by it's users.
|
36
|
+
|
37
|
+
email: adam.ciganek@gmail.com
|
38
|
+
executables: []
|
39
|
+
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files:
|
43
|
+
- README.rdoc
|
44
|
+
files:
|
45
|
+
- .gitignore
|
46
|
+
- README.rdoc
|
47
|
+
- Rakefile
|
48
|
+
- VERSION
|
49
|
+
- app/models/liquid_template.rb
|
50
|
+
- lib/liquidizer.rb
|
51
|
+
- lib/liquidizer/controller_extensions.rb
|
52
|
+
- lib/liquidizer/liquid_template.rb
|
53
|
+
- lib/liquidizer/migration_extensions.rb
|
54
|
+
- lib/liquidizer/support.rb
|
55
|
+
- liquidizer.gemspec
|
56
|
+
- rails/init.rb
|
57
|
+
- test/controller_extensions_test.rb
|
58
|
+
- test/fixtures/comments/index.html.erb
|
59
|
+
- test/fixtures/posts/index.liquid
|
60
|
+
- test/fixtures/ratings/_stuff.html.erb
|
61
|
+
- test/fixtures/ratings/edit.html.erb
|
62
|
+
- test/fixtures/spams/index.html.erb
|
63
|
+
- test/liquid_template_test.rb
|
64
|
+
- test/support_test.rb
|
65
|
+
- test/test_helper.rb
|
66
|
+
has_rdoc: true
|
67
|
+
homepage: http://github.com/metatribe/liquidizer
|
68
|
+
licenses: []
|
69
|
+
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options:
|
72
|
+
- --charset=UTF-8
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
segments:
|
80
|
+
- 0
|
81
|
+
version: "0"
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
segments:
|
87
|
+
- 0
|
88
|
+
version: "0"
|
89
|
+
requirements: []
|
90
|
+
|
91
|
+
rubyforge_project:
|
92
|
+
rubygems_version: 1.3.6
|
93
|
+
signing_key:
|
94
|
+
specification_version: 3
|
95
|
+
summary: Support for Ruby on Rails views powered by Liquid and loaded from database
|
96
|
+
test_files:
|
97
|
+
- test/support_test.rb
|
98
|
+
- test/liquid_template_test.rb
|
99
|
+
- test/controller_extensions_test.rb
|
100
|
+
- test/test_helper.rb
|