erector 0.8.3 → 0.9.0.pre1
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/Gemfile +21 -0
- data/Rakefile +171 -0
- data/VERSION.yml +3 -2
- data/lib/erector.rb +3 -5
- data/lib/erector/abstract_widget.rb +76 -31
- data/lib/erector/attributes.rb +34 -0
- data/lib/erector/caching.rb +1 -0
- data/lib/erector/convenience.rb +12 -4
- data/lib/erector/dependency.rb +2 -1
- data/lib/erector/element.rb +113 -0
- data/lib/erector/erect/erect.rb +10 -7
- data/lib/erector/externals.rb +2 -1
- data/lib/erector/html.rb +6 -340
- data/lib/erector/html_widget.rb +300 -0
- data/lib/erector/inline.rb +1 -1
- data/lib/erector/output.rb +39 -12
- data/lib/erector/promise.rb +137 -0
- data/lib/erector/rails2/extensions/rails_widget.rb +1 -1
- data/lib/erector/rails3.rb +1 -1
- data/lib/erector/sass.rb +14 -19
- data/lib/erector/tag.rb +65 -0
- data/lib/erector/text.rb +123 -0
- data/lib/erector/version.rb +1 -1
- data/lib/erector/widget.rb +52 -12
- data/lib/erector/widgets/page.rb +12 -10
- data/lib/erector/xml_widget.rb +131 -0
- data/spec/erector/caching_spec.rb +1 -0
- data/spec/erector/externals_spec.rb +0 -1
- data/spec/erector/html_spec.rb +9 -25
- data/spec/erector/output_spec.rb +102 -9
- data/spec/erector/promise_spec.rb +173 -0
- data/spec/erector/sass_spec.rb +1 -1
- data/spec/erector/tag_spec.rb +67 -0
- data/spec/erector/widget_spec.rb +53 -2
- data/spec/erector/xml_widget_spec.rb +74 -0
- data/spec/rails2/rails_app/Gemfile +1 -0
- data/spec/rails2/rails_app/spec/rails_spec_helper.rb +2 -0
- data/spec/rails_root/Gemfile +11 -0
- data/spec/rails_root/README +256 -0
- data/spec/rails_root/Rakefile +7 -0
- data/spec/rails_root/app/controllers/application.rb +6 -0
- data/spec/rails_root/app/controllers/application_controller.rb +3 -0
- data/spec/rails_root/app/helpers/application_helper.rb +2 -0
- data/spec/rails_root/app/views/layouts/application.html.erb +14 -0
- data/spec/rails_root/app/views/test/_erb.erb +1 -0
- data/spec/rails_root/app/views/test/_erector.rb +5 -0
- data/spec/rails_root/app/views/test/_partial_with_locals.rb +7 -0
- data/spec/rails_root/app/views/test/bare.rb +5 -0
- data/spec/rails_root/app/views/test/erb_from_erector.html.rb +5 -0
- data/spec/rails_root/app/views/test/erector_from_erb.html.erb +1 -0
- data/spec/rails_root/app/views/test/erector_with_locals_from_erb.html.erb +6 -0
- data/spec/rails_root/app/views/test/implicit_assigns.html.rb +5 -0
- data/spec/rails_root/app/views/test/needs.html.rb +7 -0
- data/spec/rails_root/app/views/test/needs_subclass.html.rb +5 -0
- data/spec/rails_root/app/views/test/protected_instance_variable.html.rb +5 -0
- data/spec/rails_root/app/views/test/render_default.html.rb +5 -0
- data/spec/rails_root/app/views/test/render_partial.html.rb +5 -0
- data/spec/rails_root/config.ru +4 -0
- data/spec/rails_root/config/application.rb +42 -0
- data/spec/rails_root/config/boot.rb +13 -0
- data/spec/rails_root/config/database.yml +22 -0
- data/spec/rails_root/config/environment.rb +5 -0
- data/spec/rails_root/config/environments/development.rb +22 -0
- data/spec/rails_root/config/environments/production.rb +49 -0
- data/spec/rails_root/config/environments/test.rb +35 -0
- data/spec/rails_root/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails_root/config/initializers/inflections.rb +10 -0
- data/spec/rails_root/config/initializers/mime_types.rb +5 -0
- data/spec/rails_root/config/initializers/secret_token.rb +7 -0
- data/spec/rails_root/config/initializers/session_store.rb +8 -0
- data/spec/rails_root/config/locales/en.yml +5 -0
- data/spec/rails_root/config/routes.rb +58 -0
- data/spec/rails_root/db/seeds.rb +7 -0
- data/spec/rails_root/doc/README_FOR_APP +2 -0
- data/spec/rails_root/log/development.log +17 -0
- data/spec/rails_root/log/test.log +3750 -0
- data/spec/rails_root/public/404.html +26 -0
- data/spec/rails_root/public/422.html +26 -0
- data/spec/rails_root/public/500.html +26 -0
- data/spec/rails_root/public/dispatch.cgi +10 -0
- data/spec/rails_root/public/dispatch.fcgi +24 -0
- data/spec/rails_root/public/dispatch.rb +10 -0
- data/spec/rails_root/public/favicon.ico +0 -0
- data/spec/rails_root/public/images/rails.png +0 -0
- data/spec/rails_root/public/index.html +262 -0
- data/spec/rails_root/public/javascripts/application.js +2 -0
- data/spec/rails_root/public/javascripts/controls.js +965 -0
- data/spec/rails_root/public/javascripts/dragdrop.js +974 -0
- data/spec/rails_root/public/javascripts/effects.js +1123 -0
- data/spec/rails_root/public/javascripts/prototype.js +6001 -0
- data/spec/rails_root/public/javascripts/rails.js +175 -0
- data/spec/rails_root/public/robots.txt +5 -0
- data/spec/rails_root/script/about +3 -0
- data/spec/rails_root/script/console +3 -0
- data/spec/rails_root/script/destroy +3 -0
- data/spec/rails_root/script/generate +3 -0
- data/spec/rails_root/script/performance/benchmarker +3 -0
- data/spec/rails_root/script/performance/profiler +3 -0
- data/spec/rails_root/script/performance/request +3 -0
- data/spec/rails_root/script/plugin +3 -0
- data/spec/rails_root/script/process/inspector +3 -0
- data/spec/rails_root/script/process/reaper +3 -0
- data/spec/rails_root/script/process/spawner +3 -0
- data/spec/rails_root/script/rails +6 -0
- data/spec/rails_root/script/runner +3 -0
- data/spec/rails_root/script/server +3 -0
- data/spec/rails_root/spec/form_builder_spec.rb +21 -0
- data/spec/rails_root/spec/rails_helpers_spec.rb +220 -0
- data/spec/rails_root/spec/rails_spec_helper.rb +10 -0
- data/spec/rails_root/spec/rails_widget_spec.rb +83 -0
- data/spec/rails_root/spec/render_spec.rb +298 -0
- data/spec/rails_root/test/performance/browsing_test.rb +9 -0
- data/spec/rails_root/test/test_helper.rb +13 -0
- data/spec/spec_helper.rb +3 -1
- metadata +202 -66
data/Gemfile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gem "treetop", ">= 1.2.3"
|
4
|
+
|
5
|
+
group :development do
|
6
|
+
gem "activesupport", "~>3"
|
7
|
+
gem "rspec", "~>2"
|
8
|
+
gem "rubyforge"
|
9
|
+
gem "rr"
|
10
|
+
gem "nokogiri"
|
11
|
+
gem "jeweler"
|
12
|
+
gem "haml"
|
13
|
+
gem "sass"
|
14
|
+
gem "erubis"
|
15
|
+
gem "rdoc", "~>2.3"
|
16
|
+
gem "wrong", ">=0.5.4"
|
17
|
+
end
|
18
|
+
|
19
|
+
group :rails do
|
20
|
+
gem "rails", "~> 3.0.0"
|
21
|
+
end
|
data/Rakefile
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
puts "RUBY_VERSION=#{RUBY_VERSION}"
|
2
|
+
|
3
|
+
begin
|
4
|
+
# fix http://stackoverflow.com/questions/4932881/gemcutter-rake-build-now-throws-undefined-method-write-for-syckemitter
|
5
|
+
require 'psych' unless RUBY_VERSION =~ /^1\.8/
|
6
|
+
rescue LoadError
|
7
|
+
warn "Couldn't find psych; continuing."
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'rake'
|
11
|
+
require 'rake/testtask'
|
12
|
+
|
13
|
+
require "rspec/core/rake_task"
|
14
|
+
|
15
|
+
require 'rdoc'
|
16
|
+
here = File.expand_path(File.dirname(__FILE__))
|
17
|
+
$LOAD_PATH.unshift("#{here}/lib")
|
18
|
+
|
19
|
+
require "erector/version"
|
20
|
+
|
21
|
+
begin
|
22
|
+
require 'jeweler'
|
23
|
+
Jeweler::Tasks.new do |gemspec|
|
24
|
+
gemspec.version = Erector::VERSION
|
25
|
+
gemspec.name = "erector"
|
26
|
+
gemspec.summary = "HTML/XML Builder library"
|
27
|
+
gemspec.email = "erector@googlegroups.com"
|
28
|
+
gemspec.description = "Erector is a Builder-like view framework, inspired by Markaby but overcoming some of its flaws. In Erector all views are objects, not template files, which allows the full power of object-oriented programming (inheritance, modular decomposition, encapsulation) in views."
|
29
|
+
gemspec.files = FileList[
|
30
|
+
"README.txt",
|
31
|
+
"VERSION.yml",
|
32
|
+
"lib/**/*",
|
33
|
+
"bin/erector",
|
34
|
+
]
|
35
|
+
gemspec.executables = ["erector"]
|
36
|
+
specs = Dir.glob("spec/**/*") #.reject { |file| file =~ %r{spec/rails2/} }
|
37
|
+
gemspec.test_files = ([
|
38
|
+
"Rakefile",
|
39
|
+
"Gemfile",
|
40
|
+
] + specs).flatten
|
41
|
+
gemspec.homepage = "http://erector.rubyforge.org/"
|
42
|
+
gemspec.authors = [
|
43
|
+
"Alex Chaffee",
|
44
|
+
"Brian Takita",
|
45
|
+
"Jeff Dean",
|
46
|
+
"Jim Kingdon",
|
47
|
+
"John Firebaugh",
|
48
|
+
]
|
49
|
+
# gemspec.add_dependency 'treetop', ">= 1.2.3" # Jeweler now reads Gemfile, I think
|
50
|
+
end
|
51
|
+
|
52
|
+
Jeweler::RubyforgeTasks.new do |rubyforge|
|
53
|
+
rubyforge.doc_task = "rdoc"
|
54
|
+
rubyforge.remote_doc_path = "rdoc"
|
55
|
+
end
|
56
|
+
|
57
|
+
rescue LoadError
|
58
|
+
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install jeweler"
|
59
|
+
end
|
60
|
+
|
61
|
+
desc "Default: run most tests"
|
62
|
+
task :default => :spec
|
63
|
+
task :cruise => [:install_gems, :print_environment, :test]
|
64
|
+
task :test => :spec
|
65
|
+
|
66
|
+
task :install_gems do
|
67
|
+
sh "bundle check"
|
68
|
+
end
|
69
|
+
|
70
|
+
desc "Build the web site from the .rb files in web/"
|
71
|
+
task :web do
|
72
|
+
files = Dir["web/*.rb"] - ["web/page.rb", "web/sidebar.rb", "web/clickable_li.rb"]
|
73
|
+
require 'erector'
|
74
|
+
require 'erector/erect/erect'
|
75
|
+
$: << "."
|
76
|
+
Erector::Widget.prettyprint_default = true
|
77
|
+
Erector::Erect.new(["--to-html", * files]).run
|
78
|
+
end
|
79
|
+
|
80
|
+
desc "Generate rdoc"
|
81
|
+
task :docs => :rdoc
|
82
|
+
|
83
|
+
task :rdoc => :clean_rdoc
|
84
|
+
task :clean_rdoc do
|
85
|
+
FileUtils.rm_rf("rdoc")
|
86
|
+
end
|
87
|
+
|
88
|
+
# push the docs to Rubyforge
|
89
|
+
task :publish_docs => :"rubyforge:release:docs"
|
90
|
+
|
91
|
+
desc "Publish web site to RubyForge"
|
92
|
+
task :publish_web do
|
93
|
+
config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
|
94
|
+
host = "#{config["username"]}@rubyforge.org"
|
95
|
+
rubyforge_name = "erector"
|
96
|
+
remote_dir = "/var/www/gforge-projects/#{rubyforge_name}"
|
97
|
+
local_dir = "web"
|
98
|
+
rdoc_dir = "rdoc"
|
99
|
+
rsync_args = '--archive --verbose --delete'
|
100
|
+
|
101
|
+
sh %{rsync #{rsync_args} --exclude=#{rdoc_dir} #{local_dir}/ #{host}:#{remote_dir}}
|
102
|
+
end
|
103
|
+
|
104
|
+
require 'rdoc/task'
|
105
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
106
|
+
rdoc.rdoc_dir = 'rdoc'
|
107
|
+
rdoc.title = "Erector #{Erector::VERSION}"
|
108
|
+
rdoc.options << '--inline-source' << "--promiscuous"
|
109
|
+
rdoc.options << "--main=README.txt"
|
110
|
+
# rdoc.options << '--diagram' if RUBY_PLATFORM !~ /win32/ and `which dot` =~ /\/dot/ and not ENV['NODOT']
|
111
|
+
rdoc.rdoc_files.include('README.txt')
|
112
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
113
|
+
rdoc.rdoc_files.include('bin/**/*')
|
114
|
+
end
|
115
|
+
|
116
|
+
desc "Regenerate unicode.rb from UnicodeData.txt from unicode.org. Only needs to be run when there is a new version of the Unicode specification"
|
117
|
+
task(:build_unicode) do
|
118
|
+
require 'lib/erector/unicode_builder'
|
119
|
+
builder = Erector::UnicodeBuilder.new(
|
120
|
+
File.open("/usr/lib/perl5/5.8.8/unicore/UnicodeData.txt"),
|
121
|
+
File.open("lib/erector/unicode.rb", "w")
|
122
|
+
)
|
123
|
+
builder.generate
|
124
|
+
end
|
125
|
+
|
126
|
+
task :print_environment do
|
127
|
+
puts <<-ENVIRONMENT
|
128
|
+
Build environment:
|
129
|
+
#{`uname -a`.chomp}
|
130
|
+
#{`ruby -v`.chomp}
|
131
|
+
SQLite3: #{`sqlite3 -version`}
|
132
|
+
#{`gem env`}
|
133
|
+
Local gems:
|
134
|
+
#{`gem list`.gsub(/^/, ' ')}
|
135
|
+
ENVIRONMENT
|
136
|
+
end
|
137
|
+
|
138
|
+
namespace :spec do
|
139
|
+
desc "Run core specs."
|
140
|
+
RSpec::Core::RakeTask.new(:core) do |spec|
|
141
|
+
spec.pattern = 'spec/erector/*_spec.rb'
|
142
|
+
end
|
143
|
+
|
144
|
+
desc "Run specs for the 'erector' command line tool."
|
145
|
+
RSpec::Core::RakeTask.new(:erect) do |spec|
|
146
|
+
spec.pattern = 'spec/erect/*_spec.rb'
|
147
|
+
end
|
148
|
+
|
149
|
+
desc "Run specs for erector's Rails integration."
|
150
|
+
RSpec::Core::RakeTask.new(:rails) do |spec|
|
151
|
+
spec.pattern = 'spec/rails_root/spec/*_spec.rb'
|
152
|
+
end
|
153
|
+
|
154
|
+
desc "Run specs for erector's Rails integration under Rails 2."
|
155
|
+
task :rails2 do
|
156
|
+
Dir.chdir("spec/rails2/rails_app") do
|
157
|
+
# Bundler.with_clean_env do
|
158
|
+
sh "BUNDLE_GEMFILE='./Gemfile' bundle exec rake rails2"
|
159
|
+
# end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
desc "Run all specs under Rails 3.1 - prepare with 'bundle install --gemfile Gemfile-rails31'"
|
164
|
+
task :rails31 do
|
165
|
+
gemfile = "#{here}/Gemfile-rails31"
|
166
|
+
sh "BUNDLE_GEMFILE='#{gemfile}' bundle exec rake spec:core spec:erect spec:rails"
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
desc "Run most specs"
|
171
|
+
task :spec => ['spec:core', 'spec:erect', 'spec:rails', 'spec:rails2']
|
data/VERSION.yml
CHANGED
data/lib/erector.rb
CHANGED
@@ -3,11 +3,6 @@ end
|
|
3
3
|
|
4
4
|
require "cgi"
|
5
5
|
require "yaml"
|
6
|
-
begin
|
7
|
-
require "sass"
|
8
|
-
rescue LoadError => e
|
9
|
-
# oh well, no Sass
|
10
|
-
end
|
11
6
|
|
12
7
|
require "erector/raw_string"
|
13
8
|
require "erector/dependencies"
|
@@ -21,7 +16,10 @@ require "erector/html"
|
|
21
16
|
require "erector/convenience"
|
22
17
|
require "erector/jquery"
|
23
18
|
require "erector/sass"
|
19
|
+
|
24
20
|
require "erector/abstract_widget"
|
21
|
+
require "erector/xml_widget"
|
22
|
+
require "erector/html_widget"
|
25
23
|
require "erector/widget"
|
26
24
|
|
27
25
|
require "erector/inline"
|
@@ -1,8 +1,25 @@
|
|
1
|
+
require 'erector/element'
|
2
|
+
require 'erector/attributes'
|
3
|
+
require 'erector/text'
|
4
|
+
require 'erector/convenience'
|
5
|
+
require 'erector/after_initialize'
|
6
|
+
require 'erector/output'
|
7
|
+
|
1
8
|
module Erector
|
2
9
|
|
3
|
-
# Abstract base class for Widget. This pattern allows Widget to include lots
|
4
|
-
# have proper semantics for "super" in
|
10
|
+
# Abstract base class for Widget. This pattern allows Widget to include lots
|
11
|
+
# of nicely organized modules and still have proper semantics for "super" in
|
12
|
+
# subclasses. See the rdoc for Widget for the list of all the included
|
13
|
+
# modules.
|
5
14
|
class AbstractWidget
|
15
|
+
|
16
|
+
include Erector::Element
|
17
|
+
include Erector::Attributes
|
18
|
+
include Erector::Text
|
19
|
+
include Erector::AfterInitialize
|
20
|
+
|
21
|
+
include Erector::Convenience
|
22
|
+
|
6
23
|
@@prettyprint_default = false
|
7
24
|
def prettyprint_default
|
8
25
|
@@prettyprint_default
|
@@ -50,30 +67,30 @@ module Erector
|
|
50
67
|
# method and returns the string.
|
51
68
|
#
|
52
69
|
# Options:
|
53
|
-
# output:: the string to output to.
|
70
|
+
# output:: the string (or array, or Erector::Output) to output to.
|
71
|
+
# Default: a new empty string
|
54
72
|
# prettyprint:: whether Erector should add newlines and indentation.
|
55
|
-
# Default: the value of prettyprint_default (which
|
56
|
-
# by default).
|
73
|
+
# Default: the value of prettyprint_default (which, in turn,
|
74
|
+
# is false by default).
|
57
75
|
# indentation:: the amount of spaces to indent. Ignored unless prettyprint
|
58
76
|
# is true.
|
59
77
|
# max_length:: preferred maximum length of a line. Line wraps will only
|
60
|
-
# occur at space characters, so a long word may end up
|
61
|
-
# a line longer than this. If nil (default), then
|
62
|
-
# arbitrary limit to line lengths, and only
|
63
|
-
# characters and prettyprinting will
|
64
|
-
# output.
|
78
|
+
# occur at space characters, so a long word may end up
|
79
|
+
# creating a line longer than this. If nil (default), then
|
80
|
+
# there is no arbitrary limit to line lengths, and only
|
81
|
+
# internal newline characters and prettyprinting will
|
82
|
+
# determine newlines in the output.
|
65
83
|
# helpers:: a helpers object containing utility methods. Usually this is a
|
66
84
|
# Rails view object.
|
67
85
|
# content_method_name:: in case you want to call a method other than
|
68
86
|
# #content, pass its name in here.
|
69
87
|
#
|
70
|
-
def
|
71
|
-
raise "Erector::Widget#to_html takes an options hash, not a symbol. Try calling \"to_html(:content_method_name=> :#{options})\"" if options.is_a? Symbol
|
88
|
+
def render(options = {})
|
72
89
|
_render(options).to_s
|
73
90
|
end
|
74
91
|
|
75
|
-
# alias for #
|
76
|
-
# @deprecated Please use {#
|
92
|
+
# alias for #render
|
93
|
+
# @deprecated Please use {#render} instead
|
77
94
|
def to_s(*args)
|
78
95
|
unless defined? @@already_warned_to_s
|
79
96
|
$stderr.puts "Erector::Widget#to_s is deprecated. Please use #to_html instead. Called from #{caller.first}"
|
@@ -82,36 +99,39 @@ module Erector
|
|
82
99
|
to_html(*args)
|
83
100
|
end
|
84
101
|
|
85
|
-
# Entry point for rendering a widget (and all its children). Same as
|
86
|
-
# only it returns an array, for theoretical performance
|
87
|
-
# Rack server (like Sinatra or Rails Metal).
|
102
|
+
# Entry point for rendering a widget (and all its children). Same as
|
103
|
+
# #render / #to_html only it returns an array, for theoretical performance
|
104
|
+
# improvements when using a Rack server (like Sinatra or Rails Metal).
|
88
105
|
#
|
89
|
-
# # Options: see #
|
106
|
+
# # Options: see #render
|
90
107
|
def to_a(options = {})
|
91
108
|
_render(options).to_a
|
92
109
|
end
|
93
110
|
|
94
111
|
# Template method which must be overridden by all widget subclasses.
|
95
112
|
# Inside this method you call the magic #element methods which emit HTML
|
96
|
-
# and text to the output string.
|
113
|
+
# and text to the output string.
|
114
|
+
#
|
115
|
+
# If you call "super" (or don't override
|
97
116
|
# +content+, or explicitly call "call_block") then your widget will
|
98
117
|
# execute the block that was passed into its constructor. The semantics of
|
99
|
-
# this block are confusing; make sure to read the rdoc for
|
118
|
+
# this block are confusing; make sure to read the rdoc for
|
119
|
+
# Erector#call_block
|
100
120
|
def content
|
101
121
|
call_block
|
102
122
|
end
|
103
|
-
|
104
|
-
# When this method is executed, the default block that was passed in to
|
105
|
-
# the widget's constructor will be executed. The semantics of this
|
123
|
+
|
124
|
+
# When this method is executed, the default block that was passed in to
|
125
|
+
# the widget's constructor will be executed. The semantics of this
|
106
126
|
# block -- that is, what "self" is, and whether it has access to
|
107
127
|
# Erector methods like "div" and "text", and the widget's instance
|
108
128
|
# variables -- can be quite confusing. The rule is, most of the time the
|
109
129
|
# block is evaluated using "call" or "yield", which means that its scope
|
110
130
|
# is that of the caller. So if that caller is not an Erector widget, it
|
111
|
-
# will *not* have access to the Erector methods, but it *will* have access
|
131
|
+
# will *not* have access to the Erector methods, but it *will* have access
|
112
132
|
# to instance variables and methods of the calling object.
|
113
|
-
#
|
114
|
-
# If you want this block to have access to Erector methods then use
|
133
|
+
#
|
134
|
+
# If you want this block to have access to Erector methods then use
|
115
135
|
# Erector::Inline#content or Erector#inline.
|
116
136
|
def call_block
|
117
137
|
@_block.call(self) if @_block
|
@@ -122,7 +142,8 @@ module Erector
|
|
122
142
|
# the second argument is a hash used to populate its instance variables.
|
123
143
|
# If the first argument is an instance then the hash must be unspecified
|
124
144
|
# (or empty). If a block is passed to this method, then it gets set as the
|
125
|
-
# rendered widget's block
|
145
|
+
# rendered widget's block, and will be executed when that widget calls
|
146
|
+
# +call_block+ or calls +super+ from inside its +content+ method.
|
126
147
|
#
|
127
148
|
# This is the preferred way to call one widget from inside another. This
|
128
149
|
# method assures that the same output string is used, which gives better
|
@@ -140,8 +161,8 @@ module Erector
|
|
140
161
|
|
141
162
|
# Creates a whole new output string, executes the block, then converts the
|
142
163
|
# output string to a string and returns it as raw text. If at all possible
|
143
|
-
# you should avoid this method since it hurts performance, and use
|
144
|
-
# instead.
|
164
|
+
# you should avoid this method since it hurts performance, and use
|
165
|
+
# +widget+ instead.
|
145
166
|
def capture
|
146
167
|
original, @_output = output, Output.new
|
147
168
|
yield
|
@@ -152,22 +173,46 @@ module Erector
|
|
152
173
|
end
|
153
174
|
|
154
175
|
protected
|
176
|
+
# executes this widget's #content method, which emits stuff onto the
|
177
|
+
# output stream
|
155
178
|
def _render(options = {}, &block)
|
156
179
|
@_block = block if block
|
157
180
|
@_parent = options[:parent] || parent
|
158
181
|
@_helpers = options[:helpers] || parent
|
159
|
-
|
160
|
-
|
182
|
+
if options[:output]
|
183
|
+
# todo: document that either :buffer or :output can be used to specify an output buffer, and deprecate :output
|
184
|
+
if options[:output].is_a? Output
|
185
|
+
@_output = options[:output]
|
186
|
+
else
|
187
|
+
@_output = Output.new({:buffer => options[:output]}.merge(options))
|
188
|
+
end
|
189
|
+
else
|
190
|
+
@_output = Output.new(options)
|
191
|
+
end
|
161
192
|
|
162
193
|
output.widgets << self.class
|
163
194
|
send(options[:content_method_name] || :content)
|
164
195
|
output
|
165
196
|
end
|
166
197
|
|
198
|
+
# same as _render, but using a parent widget's output stream and helpers
|
167
199
|
def _render_via(parent, options = {}, &block)
|
168
200
|
_render(options.merge(:parent => parent,
|
169
201
|
:output => parent.output,
|
170
202
|
:helpers => parent.helpers), &block)
|
171
203
|
end
|
204
|
+
|
205
|
+
protected
|
206
|
+
|
207
|
+
def sort_for_xml_declaration(attributes)
|
208
|
+
# correct order is "version, encoding, standalone" (XML 1.0 section 2.8).
|
209
|
+
# But we only try to put version before encoding for now.
|
210
|
+
stringized = []
|
211
|
+
attributes.each do |key, value|
|
212
|
+
stringized << [key.to_s, value]
|
213
|
+
end
|
214
|
+
stringized.sort{|a, b| b <=> a}
|
215
|
+
end
|
216
|
+
|
172
217
|
end
|
173
218
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Erector
|
2
|
+
module Attributes
|
3
|
+
def format_attributes(attributes)
|
4
|
+
if !attributes || attributes.empty?
|
5
|
+
""
|
6
|
+
else
|
7
|
+
format_sorted(sort_attributes(attributes))
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def format_sorted(sorted)
|
12
|
+
results = ['']
|
13
|
+
sorted.each do |key, value|
|
14
|
+
if value
|
15
|
+
if value.is_a?(Array)
|
16
|
+
value = value.flatten
|
17
|
+
next if value.empty?
|
18
|
+
value = value.join(' ')
|
19
|
+
end
|
20
|
+
results << "#{key}=\"#{h(value)}\""
|
21
|
+
end
|
22
|
+
end
|
23
|
+
results.join(' ')
|
24
|
+
end
|
25
|
+
|
26
|
+
def sort_attributes(attributes)
|
27
|
+
stringized = []
|
28
|
+
attributes.each do |key, value|
|
29
|
+
stringized << [key.to_s, value]
|
30
|
+
end
|
31
|
+
stringized.sort
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|