pivotal-erector 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/README.txt +81 -0
  2. data/VERSION.yml +4 -0
  3. data/bin/erect +7 -0
  4. data/lib/erector/erect.rb +148 -0
  5. data/lib/erector/erected.rb +63 -0
  6. data/lib/erector/extensions/object.rb +18 -0
  7. data/lib/erector/indenting.rb +36 -0
  8. data/lib/erector/rails/extensions/action_controller/1.2.5/action_controller.rb +17 -0
  9. data/lib/erector/rails/extensions/action_controller/2.2.0/action_controller.rb +26 -0
  10. data/lib/erector/rails/extensions/action_controller.rb +8 -0
  11. data/lib/erector/rails/extensions/action_view.rb +21 -0
  12. data/lib/erector/rails/extensions/widget/1.2.5/widget.rb +18 -0
  13. data/lib/erector/rails/extensions/widget/2.2.0/widget.rb +36 -0
  14. data/lib/erector/rails/extensions/widget.rb +117 -0
  15. data/lib/erector/rails/supported_rails_versions.rb +14 -0
  16. data/lib/erector/rails/template_handlers/1.2.5/action_view_template_handler.rb +32 -0
  17. data/lib/erector/rails/template_handlers/2.0.0/action_view_template_handler.rb +36 -0
  18. data/lib/erector/rails/template_handlers/2.1.0/action_view_template_handler.rb +31 -0
  19. data/lib/erector/rails/template_handlers/2.2.0/action_view_template_handler.rb +46 -0
  20. data/lib/erector/rails/template_handlers/action_view_template_handler.rb +14 -0
  21. data/lib/erector/rails.rb +6 -0
  22. data/lib/erector/raw_string.rb +8 -0
  23. data/lib/erector/rhtml.treetop +156 -0
  24. data/lib/erector/unicode.rb +18185 -0
  25. data/lib/erector/unicode_builder.rb +67 -0
  26. data/lib/erector/version.rb +10 -0
  27. data/lib/erector/widget.rb +510 -0
  28. data/lib/erector/widgets/table.rb +96 -0
  29. data/lib/erector/widgets.rb +2 -0
  30. data/lib/erector.rb +16 -0
  31. data/spec/core_spec_suite.rb +3 -0
  32. data/spec/erect/erect_spec.rb +145 -0
  33. data/spec/erect/erected_spec.rb +80 -0
  34. data/spec/erect/rhtml_parser_spec.rb +318 -0
  35. data/spec/erector/indentation_spec.rb +136 -0
  36. data/spec/erector/unicode_builder_spec.rb +75 -0
  37. data/spec/erector/widget_spec.rb +657 -0
  38. data/spec/erector/widgets/table_spec.rb +99 -0
  39. data/spec/rails_spec_suite.rb +3 -0
  40. data/spec/spec_helper.rb +54 -0
  41. data/spec/spec_suite.rb +45 -0
  42. metadata +118 -0
data/README.txt ADDED
@@ -0,0 +1,81 @@
1
+ = Erector
2
+
3
+ * http://erector.rubyforge.org
4
+ * mailto:erector-devel@rubyforge.org
5
+ * http://www.pivotaltracker.com/projects/482
6
+
7
+ == DESCRIPTION
8
+
9
+ Erector is a Builder-like view framework, inspired by Markaby but overcoming
10
+ some of its flaws. In Erector all views are objects, not template files,
11
+ which allows the full power of object-oriented programming (inheritance,
12
+ modular decomposition, encapsulation) in views. See the rdoc for the
13
+ Erector::Widget class to learn how to make your own widgets, and visit the
14
+ project site at http://erector.rubyforge.org for more documentation.
15
+
16
+ == SYNOPSIS
17
+
18
+ require 'erector'
19
+
20
+ class Hello < Erector::Widget
21
+ def render
22
+ html do
23
+ head do
24
+ title "Hello"
25
+ end
26
+ body do
27
+ text "Hello, "
28
+ b "world!", :class => 'big'
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ Hello.new.to_s
35
+ => "<html><head><title>Hello</title></head><body>Hello, <b class=\"big\">world!</b></body></html>"
36
+
37
+ == REQUIREMENTS
38
+
39
+ The gem depends on rake and treetop, although this is just for using the "erect" tool,
40
+ so deployed applications won't need these. Currently it also requires rails, although
41
+ we plan to separate the rails-dependent code so you can use Erector cleanly in a non-Rails app.
42
+
43
+ == INSTALL
44
+
45
+ To install as a gem:
46
+
47
+ * sudo gem install erector
48
+
49
+ Then add "require 'erector'" to any files which need erector.
50
+
51
+ To install as a Rails plugin:
52
+
53
+ * Copy the erector source to vendor/plugins/erector in your Rails directory.
54
+
55
+ When installing this way, erector is automatically available to your Rails code
56
+ (no require directive is needed).
57
+
58
+ == LICENSE:
59
+
60
+ (The MIT License)
61
+
62
+ Copyright (c) 2007-8 Pivotal Labs
63
+
64
+ Permission is hereby granted, free of charge, to any person obtaining
65
+ a copy of this software and associated documentation files (the
66
+ "Software"), to deal in the Software without restriction, including
67
+ without limitation the rights to use, copy, modify, merge, publish,
68
+ distribute, sublicense, and/or sell copies of the Software, and to
69
+ permit persons to whom the Software is furnished to do so, subject to
70
+ the following conditions:
71
+
72
+ The above copyright notice and this permission notice shall be
73
+ included in all copies or substantial portions of the Software.
74
+
75
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
76
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
77
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
78
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
79
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
80
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
81
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 5
4
+ :patch: 1
data/bin/erect ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ dir = File.expand_path(File.dirname(__FILE__))
3
+ $LOAD_PATH.unshift("#{dir}/../lib")
4
+ require "erector"
5
+ require "erector/erect"
6
+
7
+ Erector::Erect.new(ARGV).run
@@ -0,0 +1,148 @@
1
+ require "optparse"
2
+ require "rake"
3
+ require "erector/erected" # pull this out so we don't recreate the grammar every time
4
+
5
+ module Erector
6
+ class Erect
7
+ attr_reader :files, :verbose, :mode, :output_dir
8
+ def initialize(args)
9
+ @verbose = true
10
+ @mode = :to_erector
11
+ @output_dir = nil
12
+
13
+ opts = OptionParser.new do |opts|
14
+ opts.banner = "Usage: erect [options] [file|dir]*"
15
+
16
+ opts.separator "Converts from html/rhtml files to erector widgets, or from erector widgets to html files"
17
+ opts.separator ""
18
+ opts.separator "Options:"
19
+
20
+ opts.on("-q", "--quiet",
21
+ "Operate silently except in case of error") do |quiet|
22
+ @verbose = !quiet
23
+ end
24
+
25
+ opts.on("--to-erector", "(default) Convert from html/rhtml to erector classes") do
26
+ @mode = :to_erector
27
+ end
28
+
29
+ opts.on("--to-html", "Convert from erector to html") do
30
+ @mode = :to_html
31
+ end
32
+
33
+ opts.on("-o", "--output-dir DIRECTORY", "Output files to DIRECTORY (default: output files go next to input files)") do |dir|
34
+ @output_dir = dir
35
+ end
36
+
37
+ opts.on_tail("-h", "--help", "Show this message") do
38
+ @mode = :help
39
+ puts opts
40
+ exit
41
+ end
42
+
43
+ opts.on_tail("-v", "--version", "Show version") do
44
+ puts Erector::VERSION
45
+ exit
46
+ end
47
+
48
+ end
49
+ opts.parse!(args)
50
+ @files = args
51
+ explode_dirs
52
+ end
53
+
54
+ def say(msg)
55
+ print msg if verbose
56
+ end
57
+
58
+ #todo: unit test
59
+ def explode_dirs
60
+ exploded_files = FileList.new
61
+ files.each do |file|
62
+ if File.directory?(file)
63
+ exploded_files.add(explode(file))
64
+ else
65
+ exploded_files.add(file)
66
+ end
67
+ end
68
+ @files = exploded_files
69
+ end
70
+
71
+ def explode(dir)
72
+ case mode
73
+ when :to_erector
74
+ FileList["#{dir}/**/*.rhtml", "#{dir}/**/*.html", "#{dir}/**/*.html.erb"]
75
+ when :to_html
76
+ FileList["#{dir}/**/*.rb"]
77
+ end
78
+ end
79
+
80
+ def run
81
+ self.send(mode)
82
+ end
83
+
84
+ def to_erector
85
+ files.each do |file|
86
+ say "Erecting #{file}... "
87
+ begin
88
+ e = Erector::Erected.new(file)
89
+ e.convert
90
+ say " --> #{e.filename}\n"
91
+ rescue => e
92
+ puts e
93
+ puts e.backtrace.join("\n\t")
94
+ puts
95
+ end
96
+ end
97
+ end
98
+
99
+ def to_html
100
+ files.each do |file|
101
+ say "Erecting #{file}... "
102
+ #todo: move this into Erected with better tests for the naming methods
103
+ begin
104
+ #todo: fail if file isn't a .rb file
105
+ require file
106
+ #todo: understand modulized widgets (e.g. class Foo::Bar::Baz < Erector::Widget in baz.rb)
107
+ filename = file.split('/').last.gsub(/\.rb$/, '')
108
+ widget_name = camelize(filename)
109
+ widget_class = constantize(widget_name)
110
+
111
+ if widget_class < Erector::Widget
112
+ widget = widget_class.new
113
+ #todo: skip if it's missing a no-arg constructor
114
+ dir = output_dir || File.dirname(file)
115
+ FileUtils.mkdir_p(dir)
116
+ output_file = "#{dir}/#{filename}.html"
117
+ File.open(output_file, "w") do |f|
118
+ f.puts widget.to_s
119
+ end
120
+ say " --> #{output_file}\n"
121
+ else
122
+ say " -- not a widget, skipping\n"
123
+ end
124
+ rescue => e
125
+ puts e
126
+ puts e.backtrace.join("\n\t")
127
+ end
128
+ end
129
+ end
130
+
131
+ # stolen from activesuppport/lib/inflector.rb
132
+ def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
133
+ if first_letter_in_uppercase
134
+ lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
135
+ else
136
+ lower_case_and_underscored_word.first + camelize(lower_case_and_underscored_word)[1..-1]
137
+ end
138
+ end
139
+ def constantize(camel_cased_word)
140
+ unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ camel_cased_word
141
+ raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!"
142
+ end
143
+ Object.module_eval("::#{$1}", __FILE__, __LINE__)
144
+ end
145
+
146
+
147
+ end
148
+ end
@@ -0,0 +1,63 @@
1
+ require 'rubygems'
2
+ require 'treetop'
3
+ dir = File.dirname(__FILE__)
4
+ require "#{dir}/indenting"
5
+ Treetop.load("#{dir}/rhtml.treetop")
6
+
7
+ module Erector
8
+ class Erected
9
+ def initialize(in_file)
10
+ @in_file = in_file
11
+ end
12
+
13
+ def filename
14
+ dir + basename + ".rb"
15
+ end
16
+
17
+ def classname
18
+ base = classize(basename)
19
+ parent = File.dirname(@in_file)
20
+ grandparent = File.dirname(parent)
21
+ if File.basename(grandparent) == "views"
22
+ base = "Views::" + classize(File.basename(parent)) + "::" + base
23
+ end
24
+ base
25
+ end
26
+
27
+ def text
28
+ File.read(@in_file)
29
+ end
30
+
31
+ def convert
32
+ parser = RhtmlParser.new
33
+ parsed = parser.parse(File.read(@in_file))
34
+ if parsed.nil?
35
+ raise "Could not parse #{@in_file}\n" +
36
+ parser.failure_reason
37
+ else
38
+ File.open(filename, "w") do |f|
39
+ f.puts("class #{classname} < Erector::Widget")
40
+ f.puts(" def render")
41
+ f.puts(parsed.set_indent(2).convert)
42
+ f.puts(" end")
43
+ f.puts("end")
44
+ end
45
+ end
46
+ end
47
+
48
+ protected
49
+
50
+ def basename
51
+ @in_file.split("/").last.gsub(/\..*$/, '')
52
+ end
53
+
54
+ def dir
55
+ x = File.dirname(@in_file)
56
+ return (x == ".") ? "" : "#{x}/"
57
+ end
58
+
59
+ def classize(filename)
60
+ filename.split("_").map{|part| part.capitalize}.join
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,18 @@
1
+ class Object
2
+ def metaclass
3
+ class << self; self; end
4
+ end
5
+
6
+ def html_escape
7
+ return CGI.escapeHTML(to_s)
8
+ end
9
+
10
+ def html_unescape
11
+ CGI.unescapeHTML(to_s)
12
+ end
13
+
14
+ def escape_single_quotes
15
+ self.gsub(/[']/, '\\\\\'')
16
+ end
17
+ end
18
+
@@ -0,0 +1,36 @@
1
+ require 'rubygems'
2
+ require 'treetop'
3
+
4
+ module Erector
5
+ class Indenting < Treetop::Runtime::SyntaxNode #:nodoc:
6
+ @@indent = 0
7
+
8
+ def set_indent(x)
9
+ @@indent = x
10
+ self
11
+ end
12
+
13
+ def indent
14
+ [0, @@indent].max
15
+ end
16
+
17
+ def indented(s)
18
+ " " * indent + s + "\n"
19
+ end
20
+
21
+ def line(s)
22
+ indented(s)
23
+ end
24
+
25
+ def line_in(s)
26
+ s = indented(s)
27
+ @@indent += 1
28
+ s
29
+ end
30
+
31
+ def line_out(s)
32
+ @@indent -= 1
33
+ indented(s)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,17 @@
1
+ ActionController::Base.class_eval do
2
+ def render_widget(widget_class, assigns=@assigns)
3
+ @__widget_class = widget_class
4
+ @__widget_assigns = assigns
5
+ add_variables_to_assigns
6
+ render :inline => "<% @__widget_class.new(self, @__widget_assigns, _erbout).render %>"
7
+ end
8
+
9
+ def render_with_erector_widget(*options, &block)
10
+ if options.first.is_a?(Hash) && widget = options.first.delete(:widget)
11
+ render_widget widget, @assigns, &block
12
+ else
13
+ render_without_erector_widget *options, &block
14
+ end
15
+ end
16
+ alias_method_chain :render, :erector_widget
17
+ end
@@ -0,0 +1,26 @@
1
+ ActionController::Base.class_eval do
2
+ def render_widget(widget_class, assigns=nil)
3
+ @__widget_class = widget_class
4
+ if assigns
5
+ @__widget_assigns = assigns
6
+ else
7
+ @__widget_assigns = {}
8
+ variables = instance_variable_names
9
+ variables -= protected_instance_variables
10
+ variables.each do |name|
11
+ @__widget_assigns[name.sub('@', "")] = instance_variable_get(name)
12
+ end
13
+ end
14
+ response.template.send(:_evaluate_assigns_and_ivars)
15
+ render :inline => "<% @__widget_class.new(self, @__widget_assigns, output_buffer).render %>"
16
+ end
17
+
18
+ def render_with_erector_widget(*options, &block)
19
+ if options.first.is_a?(Hash) && widget = options.first.delete(:widget)
20
+ render_widget widget, @assigns, &block
21
+ else
22
+ render_without_erector_widget *options, &block
23
+ end
24
+ end
25
+ alias_method_chain :render, :erector_widget
26
+ end
@@ -0,0 +1,8 @@
1
+ dir = File.dirname(__FILE__)
2
+ if (
3
+ ActionController::Base.instance_methods + ActionController::Base.private_instance_methods).
4
+ include?("add_variables_to_assigns")
5
+ require File.expand_path("#{dir}/action_controller/1.2.5/action_controller")
6
+ else
7
+ require File.expand_path("#{dir}/action_controller/2.2.0/action_controller")
8
+ end
@@ -0,0 +1,21 @@
1
+ unless ActionView.const_defined?(:Template)
2
+ ActionView::Base.class_eval do
3
+ attr_reader :template_file_path
4
+ def render_template_with_saving_file_path(template_extension, template, file_path = nil, local_assigns = {})
5
+ @template_file_path = file_path
6
+ render_template_without_saving_file_path(template_extension, template, file_path, local_assigns)
7
+ end
8
+ alias_method_chain :render_template, :saving_file_path
9
+
10
+ def render_partial_with_notification(*args, &blk)
11
+ @is_partial_template = true
12
+ render_partial_without_notification(*args, &blk)
13
+ end
14
+ alias_method_chain :render_partial, :notification
15
+
16
+ def is_partial_template?
17
+ @is_partial_template || false
18
+ end
19
+ end
20
+ end
21
+
@@ -0,0 +1,18 @@
1
+ module Erector
2
+ Widget.class_eval do
3
+ attr_reader :_erbout
4
+
5
+ after_initialize do
6
+ @_erbout = output
7
+ end
8
+
9
+ def define_javascript_functions(*args)
10
+ begin
11
+ text raw(helpers.define_javascript_functions(*args))
12
+ rescue => e
13
+ puts e.backtrace.join("\n\t")
14
+ raise e
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,36 @@
1
+ module Erector
2
+ Widget.class_eval do
3
+ def output
4
+ process_output_buffer || @output
5
+ end
6
+
7
+ def capture_with_helpers(&block)
8
+ helpers ? helpers.capture(&block) : capture_without_helpers(&block)
9
+ end
10
+
11
+ alias_method_chain :capture, :helpers
12
+
13
+ # This is here to force #helpers.capture to return the output
14
+ def __in_erb_template; end
15
+
16
+ private
17
+
18
+ def process_output_buffer
19
+ if helpers.respond_to?(:output_buffer)
20
+ buffer = helpers.output_buffer
21
+ buffer.is_a?(String) ? buffer : handle_rjs_buffer
22
+ else
23
+ nil
24
+ end
25
+ end
26
+
27
+ def handle_rjs_buffer
28
+ returning buffer = helpers.output_buffer.dup.to_s do
29
+ helpers.output_buffer.clear
30
+ helpers.with_output_buffer(buffer) do
31
+ buffer << helpers.output_buffer.to_s
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,117 @@
1
+ module Erector
2
+ Widget.class_eval do
3
+ include ActionController::UrlWriter
4
+
5
+ # helpers returning raw text
6
+ [
7
+ :image_tag,
8
+ :javascript_include_tag,
9
+ :stylesheet_link_tag,
10
+ :sortable_element,
11
+ :sortable_element_js,
12
+ :text_field_with_auto_complete,
13
+ ].each do |helper_name|
14
+ define_method helper_name do |*args|
15
+ begin
16
+ text raw(helpers.send(helper_name, *args))
17
+ rescue => e
18
+ puts e.backtrace.join("\n\t")
19
+ raise e
20
+ end
21
+ end
22
+ end
23
+
24
+ # helpers returning raw text whose first parameter is HTML escaped
25
+ [
26
+ :link_to,
27
+ :link_to_remote,
28
+ :mail_to,
29
+ :button_to,
30
+ :submit_tag,
31
+ ].each do |helper_name|
32
+
33
+ method_def =<<-METHOD_DEF
34
+ def #{helper_name}(link_text, *args, &block)
35
+ text raw(helpers.#{helper_name}(h(link_text), *args, &block))
36
+ end
37
+ METHOD_DEF
38
+ eval(method_def)
39
+ end
40
+
41
+ def error_messages_for(*args)
42
+ text raw(helpers.error_messages_for(*args))
43
+ end
44
+
45
+ # return text, take block
46
+ [
47
+ :link_to_function,
48
+ :text_field_tag,
49
+ :password_field_tag,
50
+ :check_box_tag
51
+ ].each do |method_to_proxy_with_block|
52
+ method_def =<<-METHOD_DEF
53
+ def #{method_to_proxy_with_block}(*args, &block)
54
+ text raw(helpers.#{method_to_proxy_with_block}(*args, &block))
55
+ end
56
+ METHOD_DEF
57
+ eval(method_def)
58
+ end
59
+
60
+ # render text, take block
61
+ [
62
+ :error_messages_for,
63
+ :form_tag,
64
+ :form_for,
65
+ ].each do |method_to_proxy_with_block|
66
+ method_def =<<-METHOD_DEF
67
+ def #{method_to_proxy_with_block}(*args, &block)
68
+ helpers.#{method_to_proxy_with_block}(*args, &block)
69
+ end
70
+ METHOD_DEF
71
+ eval(method_def)
72
+ end
73
+
74
+ def javascript_include_merged(key)
75
+ helpers.javascript_include_merged(key)
76
+ end
77
+
78
+ def stylesheet_link_merged(key)
79
+ helpers.stylesheet_link_merged(key)
80
+ end
81
+
82
+ def flash
83
+ helpers.controller.send(:flash)
84
+ end
85
+
86
+ def session
87
+ helpers.controller.session
88
+ end
89
+
90
+ def controller
91
+ helpers.controller
92
+ end
93
+
94
+ def cycle(*args)
95
+ helpers.cycle(*args)
96
+ end
97
+
98
+ def simple_format(string)
99
+ p raw(string.to_s.html_escape.gsub(/\r\n?/, "\n").gsub(/\n/, "<br/>\n"))
100
+ end
101
+
102
+ def time_ago_in_words(*args)
103
+ helpers.time_ago_in_words(*args)
104
+ end
105
+
106
+ def pluralize(*args)
107
+ helpers.pluralize(*args)
108
+ end
109
+ end
110
+ end
111
+
112
+ dir = File.dirname(__FILE__)
113
+ if ActionView::Base.instance_methods.include?("output_buffer")
114
+ require "#{dir}/widget/2.2.0/widget"
115
+ else
116
+ require "#{dir}/widget/1.2.5/widget"
117
+ end
@@ -0,0 +1,14 @@
1
+ module Erector
2
+ module Rails
3
+ SUPPORTED_RAILS_VERSIONS = {
4
+ # "1.2.5" => {'version' => '1.2.5', 'git_tag' => 'v1.2.5'},
5
+ "1.99.0" => {'version' => '1.99.0', 'git_tag' => 'v2.0.0_RC1'},
6
+ "2.0.2" => {'version' => '2.0.2', 'git_tag' => 'v2.0.2'},
7
+ "2.1.0" => {'version' => '2.1.0', 'git_tag' => 'v2.1.0'},
8
+ "2.2.0" => {'version' => '2.2.0', 'git_tag' => 'v2.2.0'},
9
+ "2.2.2" => {'version' => '2.2.2', 'git_tag' => 'v2.2.2'},
10
+ "2.3.2" => {'version' => '2.3.2', 'git_tag' => 'v2.3.2'},
11
+ # "edge" => {'version' => 'edge', 'git_tag' => 'master'}, #TODO: Readd edge support
12
+ }
13
+ end
14
+ end
@@ -0,0 +1,32 @@
1
+ module ActionView #:nodoc:
2
+ module TemplateHandlers #:nodoc:
3
+ class Erector
4
+ def self.line_offset
5
+ 2
6
+ end
7
+
8
+ attr_reader :view
9
+ def initialize(view)
10
+ @view = view
11
+ end
12
+
13
+ def compilable?
14
+ true
15
+ end
16
+
17
+ ActionView::Base.register_template_handler :rb, ActionView::TemplateHandlers::Erector
18
+
19
+ def render(template, local_assigns)
20
+ relative_path_parts = view.first_render.split('/')
21
+ require_dependency view.template_file_path
22
+
23
+ dot_rb = /\.rb$/
24
+ widget_class = relative_path_parts.inject(Views) do |mod, node|
25
+ mod.const_get(node.gsub(dot_rb, '').gsub(".html", "").camelize)
26
+ end
27
+ render_method = view.is_partial_template? ? 'render_partial' : 'render'
28
+ widget_class.new(view, view.assigns).to_s(render_method)
29
+ end
30
+ end
31
+ end
32
+ end