mynyml-merb_simple_views 0.5.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/CHANGELOG +0 -0
- data/LICENSE +0 -0
- data/README +158 -0
- data/Rakefile +49 -0
- data/TODO +0 -0
- data/autotest/discover.rb +2 -0
- data/autotest/rspec_simpleviews.rb +106 -0
- data/lib/merb_simple_views.rb +33 -0
- data/lib/merb_simple_views/mixin.rb +84 -0
- data/lib/merb_simple_views/template_parser.rb +93 -0
- data/spec/mixin_spec.rb +160 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/template_parser_spec.rb +52 -0
- metadata +93 -0
data/CHANGELOG
ADDED
File without changes
|
data/LICENSE
ADDED
File without changes
|
data/README
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
merb_simple_views *ALPHA*
|
2
|
+
==============================
|
3
|
+
|
4
|
+
WARNING: This plugin is a rewrite of merb-in-file-templates for merb >= 1.0 It
|
5
|
+
is very much a work in progress, and is NOT yet stable! Feel free to contribute
|
6
|
+
or fork if you are interesting though.
|
7
|
+
|
8
|
+
UPDATE: Due to the direction the merb project has taken, this plugin's
|
9
|
+
development has been put on hold indefinitly.
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
A plugin for the Merb framework that allows templates (views) to be defined in
|
14
|
+
the same file as the controller (Sinatra style). Especially useful for
|
15
|
+
--very-flat apps (making them truly flat), apps that have litle/small view
|
16
|
+
code, and for rapid prototyping.
|
17
|
+
|
18
|
+
==== Features
|
19
|
+
* Seamless integration with #render, #display
|
20
|
+
* Respects template reloading
|
21
|
+
* Very simple to use
|
22
|
+
* Flexible
|
23
|
+
|
24
|
+
==== Dependencies
|
25
|
+
* Merb > 0.9.4 (?)
|
26
|
+
* Rspec to run the specs
|
27
|
+
|
28
|
+
==== Examples
|
29
|
+
#example for --very-flat app (single file app)
|
30
|
+
|
31
|
+
#...
|
32
|
+
class Application < Merb::Controller; end
|
33
|
+
class Products < Application
|
34
|
+
def index
|
35
|
+
@products = Product.all
|
36
|
+
render
|
37
|
+
end
|
38
|
+
def show
|
39
|
+
@product = Product[params[:id]]
|
40
|
+
render
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
__END__
|
45
|
+
@@ index.html.erb
|
46
|
+
<h1>Product List</h1>
|
47
|
+
<ul>
|
48
|
+
<% for product in @products -%>
|
49
|
+
<li><%= product.name %></li>
|
50
|
+
<% end -%>
|
51
|
+
</ul>
|
52
|
+
|
53
|
+
@@ show.html.erb
|
54
|
+
<h1><%= @product.name %></h1>
|
55
|
+
|
56
|
+
In-file templates cohabit peacefully with regular external templates. So in the
|
57
|
+
above example, show.html.erb could be defined in views/products/show.html.erb
|
58
|
+
and both templates will still be picked up normally. In case of a name conflict
|
59
|
+
between an in-file and an external template, the external one will take
|
60
|
+
precedence and won't be overwritten, keeping it safe from data loss.
|
61
|
+
|
62
|
+
Template names follow the same rules as regular templates (usually
|
63
|
+
action.mime_type.templating_engine).
|
64
|
+
|
65
|
+
Layouts, stylesheets and javascript can also be placed in in-file templates.
|
66
|
+
|
67
|
+
#...
|
68
|
+
|
69
|
+
__END__
|
70
|
+
@@ layout/application.css
|
71
|
+
#...
|
72
|
+
|
73
|
+
@@ layout/products.css
|
74
|
+
#...
|
75
|
+
|
76
|
+
@@ stylesheets/application.css
|
77
|
+
#...
|
78
|
+
|
79
|
+
@@ javascripts/jquery.js
|
80
|
+
#...
|
81
|
+
|
82
|
+
==== Tweaking
|
83
|
+
In order to be fed into merb's templating system, in-file templates need to be
|
84
|
+
written to external files. This means you will see dynamically created view
|
85
|
+
files inside your Merb.dir_for(:view) directory/subdirectories.
|
86
|
+
|
87
|
+
The directory in which files are stored is chosen based on the templating
|
88
|
+
system's native mechanisms, and so merb-in-file-templates will respect any
|
89
|
+
changes to it. Therefore if you want to change where template files are stored,
|
90
|
+
you can play with Merb.push_path(:view, ...) and the controller's
|
91
|
+
#_template_location method.
|
92
|
+
|
93
|
+
Merb.push_path(:view, Merb.root / 'views')
|
94
|
+
class Application
|
95
|
+
def _template_location(context, type=nil, controller = controller_name)
|
96
|
+
"#{controller}.#{action_name}.#{type}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
This will tell Merb to look under the /views directory, for a template named
|
101
|
+
products.index.html.erb.
|
102
|
+
|
103
|
+
want even flatter?
|
104
|
+
|
105
|
+
Merb.push_path(:view, Merb.root)
|
106
|
+
class Application
|
107
|
+
def _template_location(context, type=nil, controller=controller_name)
|
108
|
+
"view.#{controller}.#{action_name}.#{type}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
will give you a template under the root dir called view.products.index.html.erb
|
113
|
+
(adding a common prefix, 'view.' in the example above, causes template files to
|
114
|
+
show up nicely grouped with ls, file managers, etc, so they look organized even
|
115
|
+
without being placed in a subdirectory).
|
116
|
+
|
117
|
+
If you mix in-file and external templates and you don't want them to be mixed
|
118
|
+
in the same directories, you can tell merb-in-file-templates to store its
|
119
|
+
templates somewhere else. This is done through the config hash:
|
120
|
+
|
121
|
+
Merb::Plugins.config[:in_file_templates] = {
|
122
|
+
:view_root => '...',
|
123
|
+
:stylesheets_root => '...',
|
124
|
+
:javascripts_root => '...',
|
125
|
+
}
|
126
|
+
|
127
|
+
For example, you could set
|
128
|
+
|
129
|
+
:view_root => Merb.root / 'tmp' / 'ift_views'
|
130
|
+
|
131
|
+
to store your files in merb-root/tmp/ift_views, or
|
132
|
+
|
133
|
+
:view_root => '/tmp'
|
134
|
+
|
135
|
+
to store files in your system's tmp directory.
|
136
|
+
|
137
|
+
Same goes for stylesheets and javascripts, but remember that those need to be
|
138
|
+
placed in a public directory, and that they need to be referenced properly from
|
139
|
+
within your html header. You can use the controller's
|
140
|
+
#ift_dir_for(:stylesheets) and #ift_dir_for(:javascripts) methods to find their
|
141
|
+
locations.
|
142
|
+
|
143
|
+
==== Rake Task
|
144
|
+
TODO
|
145
|
+
(cleanup rake task before deployment..)
|
146
|
+
|
147
|
+
==== Installation
|
148
|
+
TODO
|
149
|
+
|
150
|
+
==== Contact
|
151
|
+
If you have suggestions, comments, a patch, a git pull request, rants, doc
|
152
|
+
fixes/improvements, etc., feel free to contact me: mynyml at gmail,
|
153
|
+
irc.freenode.net #rubyonrails, #merb
|
154
|
+
|
155
|
+
Happy Hacking!
|
156
|
+
|
157
|
+
-------------------------------------------------------------------------
|
158
|
+
Copyright (c) 2008 Martin Aumont (mynyml), released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'rake/gempackagetask'
|
2
|
+
require 'pathname'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
def gem
|
6
|
+
RUBY_1_9 ? 'gem19' : 'gem'
|
7
|
+
end
|
8
|
+
|
9
|
+
def all_except(paths)
|
10
|
+
Dir['**/*'] - paths.map {|path| path.strip.gsub(/^\//,'').gsub(/\/$/,'') }
|
11
|
+
end
|
12
|
+
|
13
|
+
spec = Gem::Specification.new do |s|
|
14
|
+
s.name = 'merb_simple_views'
|
15
|
+
s.version = '0.5.0'
|
16
|
+
s.summary = 'Merb plugin that allows defining templates (views, css, js)in the same file as the controller.'
|
17
|
+
s.description = 'Merb plugin that allows defining templates (views, css, js)in the same file as the controller.'
|
18
|
+
s.author = "Martin Aumont"
|
19
|
+
s.email = 'mynyml@gmail.com'
|
20
|
+
s.homepage = ''
|
21
|
+
s.has_rdoc = true
|
22
|
+
s.require_path = "lib"
|
23
|
+
s.files = all_except(%w( tmp/* log/* ))
|
24
|
+
s.add_dependency 'merb-core >= 1.0'
|
25
|
+
end
|
26
|
+
|
27
|
+
Rake::GemPackageTask.new(spec) do |p|
|
28
|
+
p.gem_spec = spec
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
desc "Remove package products"
|
33
|
+
task :clean => :clobber_package
|
34
|
+
|
35
|
+
desc "Update the gemspec for GitHub's gem server"
|
36
|
+
task :gemspec do
|
37
|
+
Pathname("#{spec.name}.gemspec").open('w') {|f| f << YAML.dump(spec) }
|
38
|
+
end
|
39
|
+
|
40
|
+
desc "Install gem"
|
41
|
+
task :install => [:clobber, :package] do
|
42
|
+
sh "#{SUDO} #{gem} install pkg/#{spec.full_name}.gem"
|
43
|
+
end
|
44
|
+
|
45
|
+
desc "Uninstall gem"
|
46
|
+
task :uninstall => :clean do
|
47
|
+
sh "#{SUDO} #{gem} uninstall -v #{spec.version} -x #{spec.name}"
|
48
|
+
end
|
49
|
+
|
data/TODO
ADDED
File without changes
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# adaptest from autotest/merb_rspec.rb
|
2
|
+
require 'autotest'
|
3
|
+
|
4
|
+
class RspecCommandError < StandardError; end
|
5
|
+
|
6
|
+
class Autotest::RspecSimpleviews < Autotest
|
7
|
+
def initialize
|
8
|
+
super
|
9
|
+
|
10
|
+
# Ignore any happenings in these directories
|
11
|
+
add_exception %r%^\./(?:doc|log|tmp|autotest|bin|\.git|\.autotest)%
|
12
|
+
|
13
|
+
# Ignore any mappings that Autotest may have already set up
|
14
|
+
clear_mappings
|
15
|
+
|
16
|
+
# run all specs if spec_helper is modified
|
17
|
+
add_mapping %r%^spec/spec_helper\.rb% do |_,_|
|
18
|
+
all_specs
|
19
|
+
end
|
20
|
+
|
21
|
+
# run all specs if main lib file is modified
|
22
|
+
add_mapping %r%^lib/merb_simple_views\.rb% do |_,_|
|
23
|
+
all_specs
|
24
|
+
end
|
25
|
+
|
26
|
+
# changing a lib file runs corresponding spec
|
27
|
+
add_mapping %r%^lib/merb_simple_views/(.*)\.rb% do |_, m|
|
28
|
+
files_matching %r%^spec/.*#{m[1]}_spec\.rb$%
|
29
|
+
end
|
30
|
+
|
31
|
+
# Changing a spec will cause it to run itself
|
32
|
+
add_mapping %r%^spec/.*_spec\.rb$% do |filename, _|
|
33
|
+
filename
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
39
|
+
|
40
|
+
def failed_results(results)
|
41
|
+
results.scan(/^\d+\)\n(?:\e\[\d*m)?(?:.*?Error in )?'([^\n]*)'(?: FAILED)?(?:\e\[\d*m)?\n(.*?)\n\n/m)
|
42
|
+
end
|
43
|
+
|
44
|
+
def handle_results(results)
|
45
|
+
@failures = failed_results(results)
|
46
|
+
@files_to_test = consolidate_failures(@failures)
|
47
|
+
@files_to_test.empty? && !$TESTING ? hook(:green) : hook(:red)
|
48
|
+
@tainted = !@files_to_test.empty?
|
49
|
+
end
|
50
|
+
|
51
|
+
def consolidate_failures(failed)
|
52
|
+
filters = Hash.new { |h,k| h[k] = [] }
|
53
|
+
failed.each do |spec, failed_trace|
|
54
|
+
if f = test_files_for(failed).find { |f| f =~ /spec\// }
|
55
|
+
filters[f] << spec
|
56
|
+
break
|
57
|
+
end
|
58
|
+
end
|
59
|
+
filters
|
60
|
+
end
|
61
|
+
|
62
|
+
def make_test_cmd(specs_to_runs)
|
63
|
+
[
|
64
|
+
ruby,
|
65
|
+
"-S",
|
66
|
+
spec_command,
|
67
|
+
add_options_if_present,
|
68
|
+
files_to_test.keys.flatten.join(' ')
|
69
|
+
].join(' ')
|
70
|
+
end
|
71
|
+
|
72
|
+
def add_options_if_present
|
73
|
+
File.exist?("spec/spec.opts") ? "-O spec/spec.opts " : ""
|
74
|
+
end
|
75
|
+
|
76
|
+
# Finds the proper spec command to use. Precendence is set in the
|
77
|
+
# lazily-evaluated method spec_commands. Alias + Override that in
|
78
|
+
# ~/.autotest to provide a different spec command then the default
|
79
|
+
# paths provided.
|
80
|
+
def spec_command(separator=File::ALT_SEPARATOR)
|
81
|
+
unless defined?(@spec_command)
|
82
|
+
@spec_command = spec_commands.find { |cmd| File.exists?(cmd) }
|
83
|
+
|
84
|
+
raise RspecCommandError, "No spec command could be found" unless @spec_command
|
85
|
+
|
86
|
+
@spec_command.gsub!(File::SEPARATOR, separator) if separator
|
87
|
+
end
|
88
|
+
@spec_command
|
89
|
+
end
|
90
|
+
|
91
|
+
# Autotest will look for spec commands in the following
|
92
|
+
# locations, in this order:
|
93
|
+
#
|
94
|
+
# * default spec bin/loader installed in Rubygems
|
95
|
+
# * any spec command found in PATH
|
96
|
+
def spec_commands
|
97
|
+
[File.join(Config::CONFIG['bindir'], 'spec'), 'spec']
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
# Runs +files_matching+ for all specs
|
103
|
+
def all_specs
|
104
|
+
files_matching %r%^spec/.*_spec\.rb$%
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
if defined?(Merb::Plugins)
|
2
|
+
dir = Pathname(__FILE__).dirname / 'merb_simple_views'
|
3
|
+
|
4
|
+
# Make Merb::RenderMixin's #render and #display methods chainable
|
5
|
+
#
|
6
|
+
# ==== Notes
|
7
|
+
# This is used as a (arguably) more elegant workaround to
|
8
|
+
# alias_method_chaining them.
|
9
|
+
#
|
10
|
+
# "We consider cases of people using alias_method_chain on Merb to be a bug in
|
11
|
+
# Merb, and try to find ways to expose enough functionality so it will not be
|
12
|
+
# required."
|
13
|
+
# -- http://yehudakatz.com/2008/05/22/the-greatest-thing-since-sliced-merb/
|
14
|
+
#
|
15
|
+
# Ideally those methods would be declared chainable within the RenderMixin
|
16
|
+
# itself and this monkey patch wouldn't be needed.
|
17
|
+
Merb::RenderMixin.module_eval do
|
18
|
+
[:render, :display].each do |name|
|
19
|
+
method = instance_method(name)
|
20
|
+
self.class.chainable { send(:define_method, name, method) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
require dir / 'template_parser'
|
25
|
+
require dir / 'mixin'
|
26
|
+
|
27
|
+
# config options
|
28
|
+
Merb::Plugins.config[:simple_views] = {}
|
29
|
+
|
30
|
+
Merb::BootLoader.after_app_loads do
|
31
|
+
Merb::Controller.class_eval { include SimpleViews::Mixin }
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module SimpleViews
|
2
|
+
|
3
|
+
TEMPLATES = {}
|
4
|
+
|
5
|
+
# Adds SimpleViews functionality to a Merb controller, allowing templates
|
6
|
+
# defined in the controller's file to serve as views. See README for more.
|
7
|
+
module Mixin
|
8
|
+
attr_reader :_template_parser
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@_template_parser = SimpleViews::TemplateParser.new
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
# In addition to default #render behaviour, parse simple views defined in
|
16
|
+
# controller's file and render them when requested, or render external
|
17
|
+
# templates otherwise.
|
18
|
+
#
|
19
|
+
# ==== Notes
|
20
|
+
# 1. Turned into a chainable method in merb_simple_views.rb
|
21
|
+
# 2. Uses a VirtualFile to trick template engines.
|
22
|
+
#
|
23
|
+
# ==== Parameters
|
24
|
+
# See Merb::RenderMixin#render
|
25
|
+
#
|
26
|
+
# ==== Options
|
27
|
+
# See Merb::RenderMixin#render
|
28
|
+
#
|
29
|
+
# ==== Returns
|
30
|
+
# See Merb::RenderMixin#render
|
31
|
+
#
|
32
|
+
# ==== Raises
|
33
|
+
# See Merb::RenderMixin#render
|
34
|
+
#
|
35
|
+
# ==== Alternatives
|
36
|
+
# See Merb::RenderMixin#render
|
37
|
+
#
|
38
|
+
# :api: public
|
39
|
+
def render(*args)
|
40
|
+
tpls_file = (@__caller_info__ || __caller_info__).first.first
|
41
|
+
self._template_parser.load(tpls_file).parse.each do |template_name, raw_content|
|
42
|
+
# no controller name if absolute view path
|
43
|
+
ctrl_name = template_name.match(/^\//) ? nil : self.controller_name
|
44
|
+
path = Merb.dir_for(:view) / self._template_location(template_name.gsub(/^\//,''), nil, ctrl_name)
|
45
|
+
file = VirtualFile.new(raw_content, path)
|
46
|
+
TEMPLATES[path.to_s] = file
|
47
|
+
end
|
48
|
+
super
|
49
|
+
end
|
50
|
+
|
51
|
+
# Wrap #display and store caller info so that #render (called internally by
|
52
|
+
# #display) knows what file to fetch template data from.
|
53
|
+
#
|
54
|
+
# ==== Notes
|
55
|
+
# Turned into a chainable method in merb_simple_views.rb
|
56
|
+
#
|
57
|
+
# ==== Parameters
|
58
|
+
# See Merb::RenderMixin#display
|
59
|
+
#
|
60
|
+
# ==== Options
|
61
|
+
# See Merb::RenderMixin#display
|
62
|
+
#
|
63
|
+
# ==== Returns
|
64
|
+
# See Merb::RenderMixin#display
|
65
|
+
#
|
66
|
+
# ==== Raises
|
67
|
+
# See Merb::RenderMixin#display
|
68
|
+
#
|
69
|
+
# ==== Alternatives
|
70
|
+
# See Merb::RenderMixin#display
|
71
|
+
#
|
72
|
+
# :api: public
|
73
|
+
def display(*args)
|
74
|
+
@__caller_info__ = __caller_info__
|
75
|
+
super
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
module Merb::Template
|
81
|
+
def self.load_template_io(path)
|
82
|
+
super || template_extensions.map {|ext| SimpleViews::TEMPLATES["#{path}.#{ext}"] }.compact.first
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module SimpleViews
|
2
|
+
class TemplateParser
|
3
|
+
# templates as a string, directly extracted from the file.
|
4
|
+
attr_accessor :raw_templates
|
5
|
+
alias :raw :raw_templates
|
6
|
+
alias :raw= :raw_templates=
|
7
|
+
|
8
|
+
# templates as a {'name' => 'content'} hash
|
9
|
+
attr_accessor :parsed_templates
|
10
|
+
alias :parsed :raw_templates
|
11
|
+
alias :parsed= :raw_templates=
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
self.raw_templates = ''
|
15
|
+
self.parsed_templates = {}
|
16
|
+
end
|
17
|
+
|
18
|
+
# Read a file and fetch its __END__ section, if any.
|
19
|
+
#
|
20
|
+
# ==== Parameters
|
21
|
+
# file<String,Pathname>:: File to find in-file templates in
|
22
|
+
#
|
23
|
+
# ==== Returns
|
24
|
+
# self
|
25
|
+
#
|
26
|
+
# :api: public
|
27
|
+
def load(file='')
|
28
|
+
file = Pathname(file)
|
29
|
+
if file.exist?
|
30
|
+
parts = file.read.split(/^__END__$/)
|
31
|
+
if parts.size > 1
|
32
|
+
self.raw_templates = parts[1].lstrip
|
33
|
+
end
|
34
|
+
end
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
# Parse templates string and extract template names and contents.
|
39
|
+
#
|
40
|
+
# Template names must be preceded with '@@', appear alone on their line,
|
41
|
+
# and follow the same conventions regular templates do. They can also be
|
42
|
+
# disabled by simply commenting out their name.
|
43
|
+
#
|
44
|
+
# ==== Parameters
|
45
|
+
# file<String,Pathname>:: File to find in-file templates in
|
46
|
+
#
|
47
|
+
# ==== Returns
|
48
|
+
# Hash:: Parsed templates as {'name' => 'content'}
|
49
|
+
#
|
50
|
+
# ==== Examples
|
51
|
+
#
|
52
|
+
# #posts_controller.rb
|
53
|
+
# [...]
|
54
|
+
# __END__
|
55
|
+
# @@ index.html.erb
|
56
|
+
# posts
|
57
|
+
#
|
58
|
+
# @@ show.html.erb
|
59
|
+
# post01
|
60
|
+
#
|
61
|
+
# #=> {'index.html.erb' => "posts", 'show.html.erb' => "post01"}
|
62
|
+
#
|
63
|
+
# To disable a template, comment out its name:
|
64
|
+
#
|
65
|
+
# __END__
|
66
|
+
# #@@ index.html.erb
|
67
|
+
# posts
|
68
|
+
#
|
69
|
+
# #=> {}
|
70
|
+
#
|
71
|
+
# ==== Notes
|
72
|
+
# Also stores the result in self.parsed_templates
|
73
|
+
#
|
74
|
+
# :api: public
|
75
|
+
def parse(file='')
|
76
|
+
self.load(file) if file
|
77
|
+
templates, current, ignore = {}, nil, false
|
78
|
+
self.raw_templates.each_line do |line|
|
79
|
+
if matches = line.strip.match(/^\s*(\#)*\s*@@\s*(.*)/)
|
80
|
+
ignore = (matches[1] && matches[1].match(/^#/)) and next #skip commented out templates
|
81
|
+
templates[current = matches[2]] = ''
|
82
|
+
elsif ignore
|
83
|
+
next
|
84
|
+
elsif current
|
85
|
+
templates[current] << line
|
86
|
+
end
|
87
|
+
end
|
88
|
+
# remove trailing witespace off every template body and template name
|
89
|
+
self.parsed_templates = templates.each {|key,value| templates[key.chomp.gsub(/[[:blank:]]|\t/,'')] = value.rstrip }
|
90
|
+
self.parsed_templates
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
data/spec/mixin_spec.rb
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe "Simple Views" do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
Merb.root.should == Pathname(__FILE__).dirname.parent.expand_path.to_s
|
7
|
+
views_dir = Pathname(Merb.root / "spec/fixtures/views")
|
8
|
+
views_dir.mkdir unless views_dir.directory?
|
9
|
+
Merb.push_path(:view, views_dir, "**/*")
|
10
|
+
end
|
11
|
+
|
12
|
+
before(:each) do
|
13
|
+
class Posts < Merb::Controller
|
14
|
+
def index() render end
|
15
|
+
def edit() render end
|
16
|
+
def quote() render end
|
17
|
+
def nohaz() render end
|
18
|
+
def random() render end
|
19
|
+
def show
|
20
|
+
obj = Object.new; def obj.to_html() '<b>x</b>' end
|
21
|
+
display(obj)
|
22
|
+
end
|
23
|
+
def new
|
24
|
+
obj = Object.new; def obj.to_html() '<b>y</b>' end
|
25
|
+
display(obj)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
class Topics < Merb::Controller
|
29
|
+
def index() render end
|
30
|
+
def quote() render end
|
31
|
+
end
|
32
|
+
# -----
|
33
|
+
@posts = Posts.new(fake_request)
|
34
|
+
@topics = Topics.new(fake_request)
|
35
|
+
# -----
|
36
|
+
clean_view_dir!
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should be injected in Merb::Controller" do
|
40
|
+
Merb::Controller.included_modules.should include(SimpleViews::Mixin)
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "parsing templates" do
|
44
|
+
|
45
|
+
it "should parse in-file templates on render" do
|
46
|
+
@posts._dispatch(:index)
|
47
|
+
@posts._template_parser.parsed_templates['index.html.erb'].should == "kittehs"
|
48
|
+
@posts.body.should == "kittehs"
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should parse in-file templates on display" do
|
52
|
+
@posts._dispatch(:show)
|
53
|
+
@posts._template_parser.parsed_templates['show.html.erb'].should == "kitteh-01"
|
54
|
+
@posts.body.should == "kitteh-01"
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should parse absolute paths" do
|
58
|
+
@posts._dispatch(:quote)
|
59
|
+
@posts._template_parser.parsed_templates['/posts/quote.html.erb'].should == "<i>kitteh-01</i>"
|
60
|
+
@posts.body.should == "<i>kitteh-01</i>"
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should let template engines parse views" do
|
64
|
+
@posts._dispatch(:random)
|
65
|
+
@posts._template_parser.parsed_templates['/posts/random.html.erb'].should == "kitteh-<%= '07' %>"
|
66
|
+
@posts.body.should == "kitteh-07"
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should respect changes to #_template_location" do
|
70
|
+
def @posts._template_location(context, type=nil, controller=controller_name)
|
71
|
+
"#{controller}.#{action_name}.#{type}"
|
72
|
+
end
|
73
|
+
@posts._dispatch(:index)
|
74
|
+
@posts.body.should == "tiny kittehs"
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "with template reloading" do
|
78
|
+
|
79
|
+
it "should reload templates when code reloading is on" do
|
80
|
+
Merb::Config[:reload_templates] = true
|
81
|
+
# -----
|
82
|
+
@posts._dispatch(:index)
|
83
|
+
@posts.body.should == "kittehs"
|
84
|
+
# -----
|
85
|
+
@posts._template_parser.stub!(:parsed_templates).and_return({'index.html.erb' => 'swapped'})
|
86
|
+
# -----
|
87
|
+
@posts._dispatch(:index)
|
88
|
+
@posts.body.should == "swapped"
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should not reload templates when code reloading is off" do
|
92
|
+
Merb::Config[:reload_templates] = false
|
93
|
+
# -----
|
94
|
+
@posts._dispatch(:index)
|
95
|
+
@posts.body.should == "kittehs"
|
96
|
+
# -----
|
97
|
+
@posts._template_parser.stub!(:parsed_templates).and_return({'index.html.erb' => 'swapped'})
|
98
|
+
# -----
|
99
|
+
@posts._dispatch(:index)
|
100
|
+
@posts.body.should == "kittehs"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe "falling back to default behaviour" do
|
105
|
+
|
106
|
+
it "should delegate to regular render control flow when no in-file template exists" do
|
107
|
+
write_template('edit.html.erb', "<i>ohaie!</i>", @posts)
|
108
|
+
@posts._dispatch(:edit)
|
109
|
+
@posts.body.should == "<i>ohaie!</i>"
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should delegate to regular display control flow when no in-file template exists" do
|
113
|
+
@posts._dispatch(:new)
|
114
|
+
@posts.body.should == "<b>y</b>"
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should raise exception when template is not found" do
|
118
|
+
lambda {
|
119
|
+
@posts._dispatch(:nohaz)
|
120
|
+
}.should raise_error(Merb::ControllerExceptions::TemplateNotFound)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "with multiple controllers" do
|
125
|
+
|
126
|
+
it "should pick up templates from the same file" do
|
127
|
+
@posts._dispatch(:quote)
|
128
|
+
@posts.body.should == "<i>kitteh-01</i>"
|
129
|
+
@topics._dispatch(:quote)
|
130
|
+
@topics.body.should == "<i>ceilingcat</i>"
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should allow different controllers to use the same, relative template" do
|
134
|
+
@posts._dispatch(:index)
|
135
|
+
@posts.body.should == "kittehs"
|
136
|
+
@topics._dispatch(:index)
|
137
|
+
@topics.body.should == "kittehs"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
__END__
|
144
|
+
@@ index.html.erb
|
145
|
+
kittehs
|
146
|
+
|
147
|
+
@@ show.html.erb
|
148
|
+
kitteh-01
|
149
|
+
|
150
|
+
@@ /posts/random.html.erb
|
151
|
+
kitteh-<%= '07' %>
|
152
|
+
|
153
|
+
@@ /posts/quote.html.erb
|
154
|
+
<i>kitteh-01</i>
|
155
|
+
|
156
|
+
@@ /topics/quote.html.erb
|
157
|
+
<i>ceilingcat</i>
|
158
|
+
|
159
|
+
@@ /posts.index.html.erb
|
160
|
+
tiny kittehs
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
$:.push File.join(File.dirname(__FILE__), '..', 'lib')
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'spec'
|
5
|
+
require 'merb-core'
|
6
|
+
require 'merb_simple_views'
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'ruby-debug'
|
10
|
+
rescue LoadError, RuntimeError
|
11
|
+
# i can haz dibugz plz?
|
12
|
+
end
|
13
|
+
|
14
|
+
Merb.start :environment => 'test', :adapter => 'runner'
|
15
|
+
|
16
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
17
|
+
# Core Extensions
|
18
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
19
|
+
# This might cause errors to slip into specs, but it beats using fixtures.
|
20
|
+
class String
|
21
|
+
def unindent
|
22
|
+
indent = self.select {|line| !line.strip.empty? }.map {|line| line.index(/[^\s]/) }.compact.min
|
23
|
+
self.gsub(/^[[:blank:]]{#{indent}}/, '')
|
24
|
+
end
|
25
|
+
def unindent!
|
26
|
+
self.replace(self.unindent)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
31
|
+
# Helpers
|
32
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
33
|
+
module Helpers
|
34
|
+
def write_template(name, content, controller)
|
35
|
+
view_path = Merb.dir_for(:view) / controller.controller_name / name
|
36
|
+
view_path.dirname.mkdir
|
37
|
+
Kernel.open(view_path, 'w+') {|file| file.write(content) }
|
38
|
+
end
|
39
|
+
|
40
|
+
def clean_view_dir!
|
41
|
+
FileUtils.rm_rf( Pathname.glob(Merb.dir_for(:view) / "*") )
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
46
|
+
# Config
|
47
|
+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
48
|
+
Spec::Runner.configure do |config|
|
49
|
+
config.include Merb::Test::RequestHelper
|
50
|
+
config.include Helpers
|
51
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe "Parser" do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@parser = SimpleViews::TemplateParser.new.load(__FILE__)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should load in-file templates" do
|
10
|
+
@parser.raw_templates.should match(/ohaie/)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "when parsing template strings" do
|
14
|
+
|
15
|
+
it "should split templates at @@ marks" do
|
16
|
+
@parser.raw = %|
|
17
|
+
@@ index
|
18
|
+
kittehs
|
19
|
+
@@ show
|
20
|
+
kitteh1
|
21
|
+
|.unindent
|
22
|
+
@parser.parse.size.should == 2
|
23
|
+
@parser.parse['index'].strip.should == 'kittehs'
|
24
|
+
@parser.parse['show'].strip.should == 'kitteh1'
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should remove trailing witespace off every template" do
|
28
|
+
@parser.raw = %|
|
29
|
+
@@ index
|
30
|
+
|
31
|
+
kittehs \t\n
|
32
|
+
|.unindent
|
33
|
+
@parser.parse['index'].should_not match(/\t\n$/)
|
34
|
+
@parser.parse['index'].should match(/^\n/)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should not be bothered by amount of spaces or tabs between marker and template name" do
|
38
|
+
@parser.raw = %|
|
39
|
+
@@index
|
40
|
+
kittehs
|
41
|
+
@@\t\sshow
|
42
|
+
kitteh1
|
43
|
+
|.unindent
|
44
|
+
@parser.parse['index'].should_not be_nil
|
45
|
+
@parser.parse['show'].should_not be_nil
|
46
|
+
@parser.parse["\t\sshow"].should be_nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
__END__
|
52
|
+
ohaie
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mynyml-merb_simple_views
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Martin Aumont
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-03-14 21:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: merb-core >= 1.0
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
description: Merb plugin that allows defining templates (views, css, js)in the same file as the controller.
|
26
|
+
email: mynyml@gmail.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files: []
|
32
|
+
|
33
|
+
files:
|
34
|
+
- CHANGELOG
|
35
|
+
- log
|
36
|
+
- lib
|
37
|
+
- lib/merb_simple_views.rb
|
38
|
+
- lib/merb_simple_views
|
39
|
+
- lib/merb_simple_views/mixin.bk.rb
|
40
|
+
- lib/merb_simple_views/cache.rb
|
41
|
+
- lib/merb_simple_views/cache.bk.rb
|
42
|
+
- lib/merb_simple_views/merbtasks.rb
|
43
|
+
- lib/merb_simple_views/merbtasks.bk.rb
|
44
|
+
- lib/merb_simple_views/mixin.rb
|
45
|
+
- lib/merb_simple_views/template_parser.rb
|
46
|
+
- lib/merb_simple_views.bk.rb
|
47
|
+
- LICENSE
|
48
|
+
- README
|
49
|
+
- Rakefile
|
50
|
+
- MYTODO
|
51
|
+
- draft
|
52
|
+
- TODO
|
53
|
+
- autotest
|
54
|
+
- autotest/rspec_simpleviews.rb
|
55
|
+
- autotest/discover.rb
|
56
|
+
- autotest/rspec_simpleviews.bk.rb
|
57
|
+
- spec
|
58
|
+
- spec/spec_helper.rb
|
59
|
+
- spec/mixin_spec.bk.rb
|
60
|
+
- spec/mixin_spec.rb
|
61
|
+
- spec/fixtures
|
62
|
+
- spec/fixtures/views
|
63
|
+
- spec/fixtures/controller3.rb
|
64
|
+
- spec/spec.opts
|
65
|
+
- spec/template_parser_spec.rb
|
66
|
+
has_rdoc: true
|
67
|
+
homepage: ""
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options: []
|
70
|
+
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: "0"
|
78
|
+
version:
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: "0"
|
84
|
+
version:
|
85
|
+
requirements: []
|
86
|
+
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 1.2.0
|
89
|
+
signing_key:
|
90
|
+
specification_version: 2
|
91
|
+
summary: Merb plugin that allows defining templates (views, css, js)in the same file as the controller.
|
92
|
+
test_files: []
|
93
|
+
|