markaby 0.5 → 0.6.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/.gitignore +4 -0
  2. data/CHANGELOG.rdoc +79 -0
  3. data/Markaby.gemspec +103 -0
  4. data/{README → README.rdoc} +14 -6
  5. data/Rakefile +71 -14
  6. data/VERSION +1 -0
  7. data/garlic.rb +29 -0
  8. data/init.rb +6 -0
  9. data/lib/markaby.rb +4 -9
  10. data/lib/markaby/builder.rb +156 -143
  11. data/lib/markaby/builder_tags.rb +64 -0
  12. data/lib/markaby/cssproxy.rb +36 -34
  13. data/lib/markaby/kernel_method.rb +7 -0
  14. data/lib/markaby/rails.rb +64 -39
  15. data/lib/markaby/rails/current.rb +46 -0
  16. data/lib/markaby/rails/deprecated.rb +124 -0
  17. data/lib/markaby/rails/rails_builder.rb +50 -0
  18. data/lib/markaby/tags.rb +158 -130
  19. data/lib/markaby/tilt.rb +21 -0
  20. data/spec/markaby/builder_spec.rb +118 -0
  21. data/spec/markaby/css_proxy_spec.rb +47 -0
  22. data/spec/markaby/fragment_spec.rb +10 -0
  23. data/spec/markaby/markaby_other_static.mab +1 -0
  24. data/spec/markaby/markaby_spec.rb +232 -0
  25. data/spec/markaby/rails/spec_helper.rb +21 -0
  26. data/spec/markaby/rails/views/markaby/_a_partial.mab +3 -0
  27. data/spec/markaby/rails/views/markaby/_partial_child_with_locals.mab +1 -0
  28. data/spec/markaby/rails/views/markaby/access_to_helpers.mab +1 -0
  29. data/spec/markaby/rails/views/markaby/broken.mab +7 -0
  30. data/spec/markaby/rails/views/markaby/correct_template_values.mab +5 -0
  31. data/spec/markaby/rails/views/markaby/form_for.mab +2 -0
  32. data/spec/markaby/rails/views/markaby/form_for_with_fields.mab +3 -0
  33. data/spec/markaby/rails/views/markaby/form_for_with_multiple_fields.mab +4 -0
  34. data/spec/markaby/rails/views/markaby/no_values_passed.mab +3 -0
  35. data/spec/markaby/rails/views/markaby/partial_parent.mab +1 -0
  36. data/spec/markaby/rails/views/markaby/partial_parent_with_locals.mab +7 -0
  37. data/spec/markaby/rails/views/markaby/render_erb_without_explicit_render_call.erb +1 -0
  38. data/spec/markaby/rails/views/markaby/render_explicit_but_empty_markaby_layout.mab +0 -0
  39. data/spec/markaby/rails/views/markaby/render_mab_without_explicit_render_call.mab +3 -0
  40. data/spec/markaby/rails/views/markaby/render_with_ivar.mab +3 -0
  41. data/spec/markaby/rails/views/markaby/renders_erb.rhtml +1 -0
  42. data/spec/markaby/rails_spec.rb +249 -0
  43. data/spec/markaby/rails_version_spec.rb +37 -0
  44. data/spec/markaby/tilt/erb.erb +1 -0
  45. data/spec/markaby/tilt/locals.mab +1 -0
  46. data/spec/markaby/tilt/markaby.mab +1 -0
  47. data/spec/markaby/tilt/markaby_other_static.mab +1 -0
  48. data/spec/markaby/tilt/render_twice.mab +1 -0
  49. data/spec/markaby/tilt/scope.mab +1 -0
  50. data/spec/markaby/tilt/yielding.mab +2 -0
  51. data/spec/markaby/tilt_spec.rb +86 -0
  52. data/spec/spec.opts +2 -0
  53. data/spec/spec_helper.rb +39 -0
  54. metadata +132 -52
  55. data/lib/markaby/metaid.rb +0 -16
  56. data/lib/markaby/template.rb +0 -12
  57. data/setup.rb +0 -1551
  58. data/test/test_markaby.rb +0 -109
  59. data/tools/rakehelp.rb +0 -106
@@ -0,0 +1,4 @@
1
+ doc
2
+ coverage
3
+ .garlic
4
+ pkg
@@ -0,0 +1,79 @@
1
+ = 0.6.6
2
+
3
+ * ruby 1.9.1 support. Closes Github Issues #10 & #11.
4
+ * Removed Tilt deprecation warnings
5
+
6
+ = 0.6.4
7
+
8
+ * Fixed a bug in which direct string values to Markaby::Builder wouldn't evaluate:
9
+ Markaby::Builder.new { 'foo' }.to_s #=> "foo"
10
+
11
+ * Fix critical bug with form_for, which was raising an error
12
+ * Introduce proxy object for form_for:
13
+
14
+ form_for :foo do |f|
15
+ f.text_field :bar
16
+ f.text_field :baz
17
+ end
18
+
19
+ * Remove support for rails 2.1.x series. We'll accept patches for them, if anyone cares enough.
20
+
21
+ == 0.6.2 / 0.6.3
22
+
23
+ * Add basic support for the Tilt templating engine (used with Sinatra):
24
+
25
+ require 'markaby'
26
+ require 'markaby/tilt'
27
+
28
+ == 0.6.1
29
+
30
+ * Support the following rails versions:
31
+ 1.2.2, 1.2.3, 1.2.4, 1.2.5, 1.2.6, 2.1.0, 2.1.1, 2.1.2, 2.2.0,
32
+ 2.2.1, 2.2.2, 2.2.3, 2.3.1, 2.3.2, 2.3.2.1, 2.3.3, 2.3.3.1, 2.3.4
33
+ * Only run rails tests when inside a rails plugins
34
+ * Run tests of the various versions of rails with garlic
35
+ * Start conversion to rspec. Use test/spec temporarily until conversion is done.
36
+
37
+ = 0.6
38
+ === 23 August, 2009
39
+
40
+ * Canonical repo changed to http://github.com/joho/markaby
41
+ * Gem moved to Github (using jeweler)
42
+ * Rails init process changed to work with rails > 2.1
43
+ * Default attributes on the root (<html>) element can now be overidden
44
+ * Reworked CssProxy, allowing attributes on hr and br
45
+ * Added Kernel#mab convenience method (require 'markaby/kernel_method')
46
+ * WhenOnRails: Can now use :locals with render_markaby
47
+ * WhenOnRails: Template errors now report line number
48
+
49
+ = 0.5
50
+ === 03 October, 2006
51
+
52
+ * XHTML Validation built in. So, if you have an invalid tag: error. Invalid attribute: error.
53
+ And two identical IDs in the same document: error. Optional, of course. But handy!
54
+ * New Markaby::Fragment class adds much flexibility. If it discovers you are using a tag as a string,
55
+ the tag is removed from the stream. (<tt>div { strong("Real") + " Giraffes" }</tt>)
56
+ * The prevailing rule now is: if you want it escaped, pass it as an arg. If not, pass it to a block.
57
+ * Again, escaped: <tt>h1("Me & You Have a Giraffe")</tt>
58
+ * And, not escaped: <tt>h1 { "<a href='/'>Home</a>" }</tt>
59
+ * Less method_missing, meaning: faster calls all around. Tag methods generated based on doctype.
60
+ * The <tt>html</tt> method doesn't write the doctype tags and meta tags. You must use <tt>xhtml_transitional</tt> or <tt>xhtml_strict</tt> methods to do that.
61
+ * The <tt>img</tt> method doesn't try to inject an empty alt tag and a zero border. No more of that.
62
+
63
+ = 0.3
64
+ === 02nd February, 2006
65
+
66
+ * Allow Markaby::Builder.new without args.
67
+ * Rails helper method render_markaby.
68
+
69
+ = 0.2
70
+ === 17th January, 2006
71
+
72
+ * Public announcement.
73
+ * DOCTYPES, head tags.
74
+ * Works with Rails helpers.
75
+
76
+ = 0.1
77
+ === 05th January, 2006
78
+
79
+ * Initial import.
@@ -0,0 +1,103 @@
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{markaby}
8
+ s.version = "0.6.6"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["_why", "Tim Fletcher", "John Barton", "spox", "smtlaissezfaire"]
12
+ s.date = %q{2010-06-02}
13
+ s.description = %q{Tim Fletcher and _why's ruby driven HTML templating system}
14
+ s.email = %q{scott@railsnewbie.com}
15
+ s.extra_rdoc_files = [
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "CHANGELOG.rdoc",
21
+ "Markaby.gemspec",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "garlic.rb",
26
+ "init.rb",
27
+ "lib/markaby.rb",
28
+ "lib/markaby/builder.rb",
29
+ "lib/markaby/builder_tags.rb",
30
+ "lib/markaby/cssproxy.rb",
31
+ "lib/markaby/kernel_method.rb",
32
+ "lib/markaby/rails.rb",
33
+ "lib/markaby/rails/current.rb",
34
+ "lib/markaby/rails/deprecated.rb",
35
+ "lib/markaby/rails/rails_builder.rb",
36
+ "lib/markaby/tags.rb",
37
+ "lib/markaby/tilt.rb",
38
+ "spec/markaby/builder_spec.rb",
39
+ "spec/markaby/css_proxy_spec.rb",
40
+ "spec/markaby/fragment_spec.rb",
41
+ "spec/markaby/markaby_other_static.mab",
42
+ "spec/markaby/markaby_spec.rb",
43
+ "spec/markaby/rails/spec_helper.rb",
44
+ "spec/markaby/rails/views/markaby/_a_partial.mab",
45
+ "spec/markaby/rails/views/markaby/_partial_child_with_locals.mab",
46
+ "spec/markaby/rails/views/markaby/access_to_helpers.mab",
47
+ "spec/markaby/rails/views/markaby/broken.mab",
48
+ "spec/markaby/rails/views/markaby/correct_template_values.mab",
49
+ "spec/markaby/rails/views/markaby/form_for.mab",
50
+ "spec/markaby/rails/views/markaby/form_for_with_fields.mab",
51
+ "spec/markaby/rails/views/markaby/form_for_with_multiple_fields.mab",
52
+ "spec/markaby/rails/views/markaby/no_values_passed.mab",
53
+ "spec/markaby/rails/views/markaby/partial_parent.mab",
54
+ "spec/markaby/rails/views/markaby/partial_parent_with_locals.mab",
55
+ "spec/markaby/rails/views/markaby/render_erb_without_explicit_render_call.erb",
56
+ "spec/markaby/rails/views/markaby/render_explicit_but_empty_markaby_layout.mab",
57
+ "spec/markaby/rails/views/markaby/render_mab_without_explicit_render_call.mab",
58
+ "spec/markaby/rails/views/markaby/render_with_ivar.mab",
59
+ "spec/markaby/rails/views/markaby/renders_erb.rhtml",
60
+ "spec/markaby/rails_spec.rb",
61
+ "spec/markaby/rails_version_spec.rb",
62
+ "spec/markaby/tilt/erb.erb",
63
+ "spec/markaby/tilt/locals.mab",
64
+ "spec/markaby/tilt/markaby.mab",
65
+ "spec/markaby/tilt/markaby_other_static.mab",
66
+ "spec/markaby/tilt/render_twice.mab",
67
+ "spec/markaby/tilt/scope.mab",
68
+ "spec/markaby/tilt/yielding.mab",
69
+ "spec/markaby/tilt_spec.rb",
70
+ "spec/spec.opts",
71
+ "spec/spec_helper.rb"
72
+ ]
73
+ s.homepage = %q{http://joho.github.com/markaby/}
74
+ s.rdoc_options = ["--charset=UTF-8"]
75
+ s.require_paths = ["lib"]
76
+ s.rubygems_version = %q{1.3.7}
77
+ s.summary = %q{Markup as Ruby, write HTML in your native Ruby tongue}
78
+ s.test_files = [
79
+ "spec/markaby/builder_spec.rb",
80
+ "spec/markaby/css_proxy_spec.rb",
81
+ "spec/markaby/fragment_spec.rb",
82
+ "spec/markaby/markaby_spec.rb",
83
+ "spec/markaby/rails/spec_helper.rb",
84
+ "spec/markaby/rails_spec.rb",
85
+ "spec/markaby/rails_version_spec.rb",
86
+ "spec/markaby/tilt_spec.rb",
87
+ "spec/spec_helper.rb"
88
+ ]
89
+
90
+ if s.respond_to? :specification_version then
91
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
92
+ s.specification_version = 3
93
+
94
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
95
+ s.add_runtime_dependency(%q<builder>, [">= 2.0.0"])
96
+ else
97
+ s.add_dependency(%q<builder>, [">= 2.0.0"])
98
+ end
99
+ else
100
+ s.add_dependency(%q<builder>, [">= 2.0.0"])
101
+ end
102
+ end
103
+
@@ -14,14 +14,20 @@ Write Rails templates in pure Ruby. Example layout:
14
14
  title 'Products: ' + action_name
15
15
  stylesheet_link_tag 'scaffold'
16
16
  end
17
-
17
+
18
18
  body do
19
19
  p flash[:notice], :style => "color: green"
20
-
20
+
21
21
  self << content_for_layout
22
22
  end
23
23
  end
24
24
 
25
+ Markaby supports many versions of rails:
26
+
27
+ 1.2.2, 1.2.3, 1.2.4, 1.2.5, 1.2.6, 2.2.0,
28
+ 2.2.1, 2.2.2, 2.2.3, 2.3.1, 2.3.2, 2.3.2.1,
29
+ 2.3.3, 2.3.3.1, 2.3.4
30
+
25
31
  == Using Markaby as a Ruby class
26
32
 
27
33
  Markaby is flaming easy to call from your Ruby classes.
@@ -69,7 +75,7 @@ that inside these blocks, <tt>self</tt> will be your Markaby::Builder object.
69
75
  When you use instance variables in these blocks, they will be instance variables
70
76
  of the Markaby::Builder object.
71
77
 
72
- This doesn't effect Rails users, but when used in regular Ruby code, it can
78
+ This doesn't affect Rails users, but when used in regular Ruby code, it can
73
79
  be a bit disorienting. You are recommended to put your Markaby code in a
74
80
  module where it won't mix with anything.
75
81
 
@@ -115,7 +121,7 @@ Which results in:
115
121
  </div>
116
122
  </div>
117
123
 
118
- == 3. Validate Your XHTML 1.0 Output
124
+ == 3. Validate Your XHTML 1.0 Output
119
125
 
120
126
  If you'd like Markaby to help you assemble valid XHTML documents,
121
127
  you can use the <tt>xhtml_transitional</tt> or <tt>xhtml_strict</tt>
@@ -209,7 +215,7 @@ won't work with this technique.
209
215
 
210
216
  = A Note About Rails Helpers
211
217
 
212
- When used in Rails templates, the Rails helper object is passed into
218
+ When used in Rails templates, the Rails helper object is passed into
213
219
  Markaby::Builder. When you call helper methods inside Markaby, the output
214
220
  from those methods will be output to the stream. This is incredibly
215
221
  handy, since most Rails helpers output HTML tags.
@@ -231,7 +237,7 @@ If for any reason you have trouble with fragments, you can just
231
237
  call the <tt>@helpers</tt> object with the method and you'll get
232
238
  the String back and nothing will be output.
233
239
 
234
- p { "Total is: #{@helper.number_to_human_size @file_bytes}" }
240
+ p { "Total is: #{@helpers.number_to_human_size @file_bytes}" }
235
241
 
236
242
  Conversely, you may call instance variables from your controller by using
237
243
  a method and its value will be returned, nothing will be output.
@@ -249,7 +255,9 @@ a method and its value will be returned, nothing will be output.
249
255
  = Credits
250
256
 
251
257
  Markaby is a work of immense hope by Tim Fletcher and why the lucky stiff.
258
+ It is maintained by joho, spox, and smtlaissezfaire.
252
259
  Thankyou for giving it a whirl.
253
260
 
254
261
  Markaby is inspired by the HTML library within cgi.rb. Hopefully it will
255
262
  turn around and take some cues.
263
+
data/Rakefile CHANGED
@@ -1,20 +1,77 @@
1
1
  require 'rake'
2
- require 'rake/testtask'
2
+ require 'spec/rake/spectask'
3
3
  require 'rake/clean'
4
- require 'rake/gempackagetask'
5
- require 'rake/rdoctask'
6
- require 'tools/rakehelp'
7
- require 'fileutils'
8
- include FileUtils
9
4
 
10
- REV = File.read(".svn/entries")[/committed-rev="(\d+)"/, 1] rescue nil
11
- VERS = ENV['VERSION'] || "0.5" + (REV ? ".#{REV}" : "")
5
+ begin
6
+ require 'hanna/rdoctask'
12
7
 
13
- task :default => [:package]
8
+ Rake::RDocTask.new do |rdoc|
9
+ rdoc.rdoc_dir = 'doc/rdoc'
10
+ rdoc.options << '--line-numbers'
11
+ rdoc.rdoc_files.add(['README.rdoc', 'CHANGELOG.rdoc', 'lib/**/*.rb'])
12
+ end
13
+ rescue LoadError
14
+ puts "Could not load hanna-rdoc. Please install with mislav-hanna package"
15
+ end
14
16
 
15
- setup_tests
16
- setup_rdoc ['README', 'CHANGELOG', 'lib/**/*.rb']
17
+ task :default => :spec
17
18
 
18
- summary = "Markup as Ruby, write HTML in your native Ruby tongue"
19
- test_file = "test/test_markaby.rb"
20
- setup_gem("markaby", VERS, "Tim Fletcher and _why", summary, [['builder', '>=2.0.0']], test_file)
19
+ desc 'Run the specs'
20
+ Spec::Rake::SpecTask.new do |t|
21
+ t.warning = false
22
+ t.spec_opts = ["--color"]
23
+ end
24
+
25
+ begin
26
+ require 'jeweler'
27
+
28
+ Jeweler::Tasks.new do |gemspec|
29
+ gemspec.name = "markaby"
30
+ gemspec.summary = "Markup as Ruby, write HTML in your native Ruby tongue"
31
+ gemspec.description = "Tim Fletcher and _why's ruby driven HTML templating system"
32
+ gemspec.email = "scott@railsnewbie.com"
33
+ gemspec.homepage = "http://joho.github.com/markaby/"
34
+ gemspec.authors = ["_why", "Tim Fletcher", "John Barton", "spox", "smtlaissezfaire"]
35
+ gemspec.add_dependency 'builder', '>=2.0.0'
36
+ end
37
+ rescue LoadError
38
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
39
+ end
40
+
41
+ desc "List any Markaby specific warnings"
42
+ task :warnings do
43
+ `ruby -w test/test_markaby.rb 2>&1`.split(/\n/).each do |line|
44
+ next unless line =~ /warning:/
45
+ next if line =~ /builder-/
46
+ puts line
47
+ end
48
+ end
49
+
50
+ desc "Start a Markaby-aware IRB session"
51
+ task :irb do
52
+ sh 'irb -I lib -r markaby -r markaby/kernel_method'
53
+ end
54
+
55
+ namespace :gemspec do
56
+ task :commit do
57
+ sh "git add ."
58
+ sh "git commit -m 'Update gemspec'"
59
+ end
60
+ end
61
+
62
+ namespace :release do
63
+ task :patch => [:spec, "version:bump:patch", :update_gemspec, :rerdoc, :tag_release, :build, :push_tags]
64
+
65
+ task :update_gemspec => ["gemspec:generate", "gemspec:validate", "gemspec:commit"]
66
+ task :tag_release do
67
+ require File.dirname(__FILE__) + "/lib/markaby"
68
+ version = "v#{Markaby::VERSION}"
69
+ sh "git tag #{version}"
70
+ end
71
+
72
+ task :push_tags do
73
+ sh "git push --tags"
74
+ end
75
+ end
76
+
77
+ task :release => "release:patch"
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.6.6
@@ -0,0 +1,29 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/lib/markaby/rails")
2
+
3
+ garlic do
4
+ # this plugin
5
+ repo "markaby", :path => '.'
6
+
7
+ # other repos
8
+ repo "rails", :url => "git://github.com/rails/rails"
9
+
10
+ # target railses
11
+ RAILS_TAREGETS = Markaby::Rails::SUPPORTED_RAILS_VERSIONS.map do |version|
12
+ "v#{version}"
13
+ end
14
+
15
+ RAILS_TAREGETS.each do |rails|
16
+ # declare how to prepare, and run each CI target
17
+ target "Rails: #{rails}", :tree_ish => rails do
18
+ prepare do
19
+ plugin "markaby", :clone => true # so we can work in targets
20
+ end
21
+
22
+ run do
23
+ cd "vendor/plugins/markaby" do
24
+ sh "rake"
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
data/init.rb ADDED
@@ -0,0 +1,6 @@
1
+ $:.unshift File.expand_path(File.join(File.dirname(__FILE__), 'lib'))
2
+
3
+ require 'markaby'
4
+ require 'markaby/rails'
5
+
6
+ Markaby::Rails.load
@@ -8,7 +8,7 @@ $:.unshift File.expand_path(File.dirname(__FILE__))
8
8
 
9
9
  # Markaby is a module containing all of the great Markaby classes that
10
10
  # do such an excellent job.
11
- #
11
+ #
12
12
  # * Markaby::Builder: the class for actually calling the Ruby methods
13
13
  # which write the HTML.
14
14
  # * Markaby::CSSProxy: a class which adds element classes and IDs to
@@ -19,17 +19,12 @@ $:.unshift File.expand_path(File.dirname(__FILE__))
19
19
  # * Markaby::Template: a class for hooking Markaby into Rails as a
20
20
  # proper templating language.
21
21
  module Markaby
22
- VERSION = '0.5'
22
+ version_file = File.expand_path(File.dirname(__FILE__) + "/../VERSION")
23
+ VERSION = File.read(version_file).strip
23
24
 
24
25
  class InvalidXhtmlError < Exception; end
25
26
  end
26
27
 
27
- unless defined?(Builder)
28
- require 'rubygems'
29
- require 'builder'
30
- end
31
-
28
+ require 'builder' unless defined?(Builder)
32
29
  require 'markaby/builder'
33
30
  require 'markaby/cssproxy'
34
- require 'markaby/metaid'
35
- require 'markaby/template'
@@ -1,6 +1,9 @@
1
1
  require 'markaby/tags'
2
+ require 'markaby/builder_tags'
2
3
 
3
4
  module Markaby
5
+ RUBY_VERSION_ID = RUBY_VERSION.split(".").join.to_i
6
+
4
7
  # The Markaby::Builder class is the central gear in the system. When using
5
8
  # from Ruby code, this is the only class you need to instantiate directly.
6
9
  #
@@ -19,33 +22,49 @@ module Markaby
19
22
  # puts mab.to_s
20
23
  #
21
24
  class Builder
25
+ include Markaby::BuilderTags
22
26
 
23
- @@default = {
24
- :indent => 0,
25
- :output_helpers => true,
27
+ DEFAULT_OPTIONS = {
28
+ :indent => 0,
29
+ :output_helpers => true,
26
30
  :output_xml_instruction => true,
27
- :output_meta_tag => true,
28
- :auto_validation => true,
29
- :tagset => Markaby::XHTMLTransitional
31
+ :output_meta_tag => true,
32
+ :auto_validation => true,
33
+ :tagset => Markaby::XHTMLTransitional,
34
+ :root_attributes => {
35
+ :xmlns => 'http://www.w3.org/1999/xhtml',
36
+ :'xml:lang' => 'en',
37
+ :lang => 'en'
38
+ }
30
39
  }
31
40
 
41
+ @@options = DEFAULT_OPTIONS.dup
42
+
43
+ def self.restore_defaults!
44
+ @@options = DEFAULT_OPTIONS.dup
45
+ end
46
+
32
47
  def self.set(option, value)
33
- @@default[option] = value
48
+ @@options[option] = value
49
+ end
50
+
51
+ def self.get(option)
52
+ @@options[option]
34
53
  end
35
54
 
36
- def self.ignored_helpers
37
- @@ignored_helpers ||= []
38
- end
39
-
40
- def self.ignore_helpers(*helpers)
41
- ignored_helpers.concat helpers
42
- end
55
+ def self.ignored_helpers
56
+ @@ignored_helpers ||= []
57
+ end
58
+
59
+ def self.ignore_helpers(*helpers)
60
+ ignored_helpers.concat helpers
61
+ end
43
62
 
44
63
  attr_accessor :output_helpers, :tagset
45
64
 
46
65
  # Create a Markaby builder object. Pass in a hash of variable assignments to
47
66
  # +assigns+ which will be available as instance variables inside tag construction
48
- # blocks. If an object is passed in to +helpers+, its methods will be available
67
+ # blocks. If an object is passed in to +helper+, its methods will be available
49
68
  # from those same blocks.
50
69
  #
51
70
  # Pass in a +block+ to new and the block will be evaluated.
@@ -58,40 +77,43 @@ module Markaby
58
77
  # end
59
78
  # }
60
79
  #
61
- def initialize(assigns = {}, helpers = nil, &block)
62
- @streams = [[]]
63
- @assigns = assigns
64
- @elements = {}
80
+ def initialize(assigns = {}, helper = nil, &block)
81
+ @streams = [Stream.new]
82
+ @assigns = assigns.dup
83
+ @_helper = helper
84
+ @used_ids = {}
65
85
 
66
- @@default.each do |k, v|
67
- instance_variable_set("@#{k}", @assigns[k] || v)
86
+ @@options.each do |k, v|
87
+ instance_variable_set("@#{k}", @assigns.delete(k) || v)
68
88
  end
69
89
 
70
- if helpers.nil?
71
- @helpers = nil
72
- else
73
- @helpers = helpers.dup
74
- for iv in helpers.instance_variables
75
- instance_variable_set(iv, helpers.instance_variable_get(iv))
76
- end
90
+ @assigns.each do |k, v|
91
+ instance_variable_set("@#{k}", v)
77
92
  end
78
93
 
79
- unless assigns.nil? || assigns.empty?
80
- for iv, val in assigns
81
- instance_variable_set("@#{iv}", val)
82
- unless @helpers.nil?
83
- @helpers.instance_variable_set("@#{iv}", val)
84
- end
85
- end
86
- end
94
+ @builder = XmlMarkup.new(:indent => @indent, :target => @streams.last)
87
95
 
88
- @builder = ::Builder::XmlMarkup.new(:indent => @indent, :target => @streams.last)
89
- class << @builder
90
- attr_accessor :target, :level
91
- end
96
+ text(capture(&block)) if block
97
+ end
92
98
 
93
- if block
94
- text(capture(&block))
99
+ def helper=(helper)
100
+ @_helper = helper
101
+ end
102
+
103
+ def metaclass(&block)
104
+ metaclass = class << self; self; end
105
+ metaclass.class_eval(&block)
106
+ end
107
+
108
+ private :metaclass
109
+
110
+ def locals=(locals)
111
+ locals.each do |key, value|
112
+ metaclass do
113
+ define_method key do
114
+ value
115
+ end
116
+ end
95
117
  end
96
118
  end
97
119
 
@@ -102,29 +124,26 @@ module Markaby
102
124
 
103
125
  # Write a +string+ to the HTML stream without escaping it.
104
126
  def text(string)
105
- @builder << "#{string}"
127
+ @builder << string.to_s
106
128
  nil
107
129
  end
108
130
  alias_method :<<, :text
109
131
  alias_method :concat, :text
110
132
 
111
- # Emulate ERB to satisfy helpers like <tt>form_for</tt>.
112
- def _erbout; self end
113
-
114
133
  # Captures the HTML code built inside the +block+. This is done by creating a new
115
134
  # stream for the builder object, running the block and passing back its stream as a string.
116
135
  #
117
136
  # >> Markaby::Builder.new.capture { h1 "TEST"; h2 "CAPTURE ME" }
118
- # => "<h1>TITLE</h1>\n<h2>CAPTURE ME</h2>\n"
137
+ # => "<h1>TEST</h1><h2>CAPTURE ME</h2>"
119
138
  #
120
139
  def capture(&block)
121
- @streams.push(builder.target = [])
140
+ @streams.push(@builder.target = Stream.new)
122
141
  @builder.level += 1
123
142
  str = instance_eval(&block)
124
143
  str = @streams.last.join if @streams.last.any?
125
144
  @streams.pop
126
145
  @builder.level -= 1
127
- builder.target = @streams.last
146
+ @builder.target = @streams.last
128
147
  str
129
148
  end
130
149
 
@@ -132,35 +151,43 @@ module Markaby
132
151
  # the arguments are the same as the tags implemented via method_missing.
133
152
  def tag!(tag, *args, &block)
134
153
  ele_id = nil
135
- if @auto_validation and @tagset
136
- if !@tagset.tagset.has_key?(tag)
137
- raise InvalidXhtmlError, "no element `#{tag}' for #{tagset.doctype}"
138
- elsif args.last.respond_to?(:to_hash)
139
- attrs = args.last.to_hash
140
- attrs.each do |k, v|
141
- atname = k.to_s.downcase.intern
142
- unless k =~ /:/ or @tagset.tagset[tag].include? atname
143
- raise InvalidXhtmlError, "no attribute `#{k}' on #{tag} elements"
144
- end
145
- if atname == :id
146
- ele_id = v.to_s
147
- if @elements.has_key? ele_id
148
- raise InvalidXhtmlError, "id `#{ele_id}' already used (id's must be unique)."
149
- end
150
- end
154
+ if @auto_validation && @tagset
155
+ if !@tagset.tagset.has_key?(tag)
156
+ raise InvalidXhtmlError, "no element `#{tag}' for #{tagset.doctype}"
157
+ elsif args.last.respond_to?(:to_hash)
158
+ attrs = args.last.to_hash
159
+
160
+ if @tagset.forms.include?(tag) && attrs[:id]
161
+ attrs[:name] ||= attrs[:id]
162
+ end
163
+
164
+ attrs.each do |k, v|
165
+ atname = k.to_s.downcase.intern
166
+ unless k =~ /:/ or @tagset.tagset[tag].include? atname
167
+ raise InvalidXhtmlError, "no attribute `#{k}' on #{tag} elements"
168
+ end
169
+ if atname == :id
170
+ ele_id = v.to_s
171
+ if @used_ids.has_key? ele_id
172
+ raise InvalidXhtmlError, "id `#{ele_id}' already used (id's must be unique)."
151
173
  end
174
+ end
152
175
  end
176
+ end
153
177
  end
178
+
154
179
  if block
155
- str = capture &block
180
+ str = capture(&block)
156
181
  block = proc { text(str) }
157
182
  end
158
183
 
159
184
  f = fragment { @builder.method_missing(tag, *args, &block) }
160
- @elements[ele_id] = f if ele_id
185
+ @used_ids[ele_id] = f if ele_id
161
186
  f
162
187
  end
163
188
 
189
+ private
190
+
164
191
  # This method is used to intercept calls to helper methods and instance
165
192
  # variables. Here is the order of interception:
166
193
  #
@@ -175,95 +202,61 @@ module Markaby
175
202
  # method_missing used to be the lynchpin in Markaby, but it's no longer used to handle
176
203
  # HTML tags. See html_tag for that.
177
204
  def method_missing(sym, *args, &block)
178
- if @helpers.respond_to?(sym, true) && !self.class.ignored_helpers.include?(sym)
179
- r = @helpers.send(sym, *args, &block)
180
- if @output_helpers and r.respond_to? :to_str
205
+ if @_helper.respond_to?(sym, true) && !self.class.ignored_helpers.include?(sym)
206
+ r = @_helper.send(sym, *args, &block)
207
+ if @output_helpers && r.respond_to?(:to_str)
181
208
  fragment { @builder << r }
182
209
  else
183
210
  r
184
211
  end
185
- elsif ::Builder::XmlMarkup.instance_methods.include?(sym.to_s)
212
+ elsif @assigns.has_key?(sym)
213
+ @assigns[sym]
214
+ elsif @assigns.has_key?(stringy_key = sym.to_s)
215
+ # Rails' ActionView assigns hash has string keys for
216
+ # instance variables that are defined in the controller.
217
+ @assigns[stringy_key]
218
+ elsif instance_variables_for(self).include?(ivar = "@#{sym}".to_sym)
219
+ instance_variable_get(ivar)
220
+ elsif @_helper && instance_variables_for(@_helper).include?(ivar)
221
+ @_helper.instance_variable_get(ivar)
222
+ elsif instance_methods_for(::Builder::XmlMarkup).include?(sym)
186
223
  @builder.__send__(sym, *args, &block)
187
- elsif instance_variables.include?("@#{sym}")
188
- instance_variable_get("@#{sym}")
189
- elsif @tagset.nil?
224
+ elsif !@tagset
190
225
  tag!(sym, *args, &block)
191
226
  else
192
- raise NoMethodError, "no such method `#{sym}'"
227
+ super
193
228
  end
194
229
  end
195
230
 
196
- # Every HTML tag method goes through an html_tag call. So, calling <tt>div</tt> is equivalent
197
- # to calling <tt>html_tag(:div)</tt>. All HTML tags in Markaby's list are given generated wrappers
198
- # for this method.
199
- #
200
- # If the @auto_validation setting is on, this method will check for many common mistakes which
201
- # could lead to invalid XHTML.
202
- def html_tag(sym, *args, &block)
203
- if @auto_validation and @tagset.self_closing.include?(sym) and block
204
- raise InvalidXhtmlError, "the `\#{sym}' element is self-closing, please remove the block"
231
+ if RUBY_VERSION_ID >= 191
232
+ def instance_variables_for(obj)
233
+ obj.instance_variables
205
234
  end
206
- if args.empty? and block.nil? and not NO_PROXY.include?(sym)
207
- return CssProxy.new do |args, block|
208
- if @tagset.forms.include?(sym) and args.last.respond_to?(:to_hash) and args.last[:id]
209
- args.last[:name] ||= args.last[:id]
210
- end
211
- tag!(sym, *args, &block)
212
- end
235
+
236
+ def instance_methods_for(obj)
237
+ obj.instance_methods
213
238
  end
214
- if not @tagset.self_closing.include?(sym) and args.first.respond_to?(:to_hash)
215
- block ||= proc{}
239
+ else
240
+ def instance_variables_for(obj)
241
+ obj.instance_variables.map { |var| var.to_sym }
216
242
  end
217
- tag!(sym, *args, &block)
218
- end
219
243
 
220
- XHTMLTransitional.tags.each do |k|
221
- class_eval %{
222
- def #{k}(*args, &block)
223
- html_tag(#{k.inspect}, *args, &block)
224
- end
225
- }
226
- end
227
-
228
- # Builds a head tag. Adds a <tt>meta</tt> tag inside with Content-Type
229
- # set to <tt>text/html; charset=utf-8</tt>.
230
- def head(*args, &block)
231
- tag!(:head, *args) do
232
- tag!(:meta, "http-equiv" => "Content-Type", "content" => "text/html; charset=utf-8") if @output_meta_tag
233
- instance_eval(&block)
244
+ def instance_methods_for(obj)
245
+ obj.instance_methods.map { |m| m.to_sym }
234
246
  end
235
247
  end
236
248
 
237
- # Builds an html tag. An XML 1.0 instruction and an XHTML 1.0 Transitional doctype
238
- # are prepended. Also assumes <tt>:xmlns => "http://www.w3.org/1999/xhtml",
239
- # :lang => "en"</tt>.
240
- def xhtml_transitional(&block)
241
- self.tagset = Markaby::XHTMLTransitional
242
- xhtml_html &block
243
- end
244
-
245
- # Builds an html tag with XHTML 1.0 Strict doctype instead.
246
- def xhtml_strict(&block)
247
- self.tagset = Markaby::XHTMLStrict
248
- xhtml_html &block
249
- end
250
-
251
- private
252
-
253
- def xhtml_html(&block)
254
- instruct! if @output_xml_instruction
255
- declare!(:DOCTYPE, :html, :PUBLIC, *tagset.doctype)
256
- tag!(:html, :xmlns => "http://www.w3.org/1999/xhtml", "xml:lang" => "en", :lang => "en", &block)
257
- end
258
-
259
249
  def fragment
260
250
  stream = @streams.last
261
- f1 = stream.length
251
+ start = stream.length
262
252
  yield
263
- f2 = stream.length - f1
264
- Fragment.new(stream, f1, f2)
253
+ length = stream.length - start
254
+ Fragment.new(stream, start, length)
265
255
  end
256
+ end
266
257
 
258
+ class Stream < Array
259
+ alias_method :to_s, :join
267
260
  end
268
261
 
269
262
  # Every tag method in Markaby returns a Fragment. If any method gets called on the Fragment,
@@ -272,17 +265,37 @@ module Markaby
272
265
  #
273
266
  # For a more practical explanation, check out the README.
274
267
  class Fragment < ::Builder::BlankSlate
275
- def initialize(s, a, b)
276
- @s, @f1, @f2 = s, a, b
268
+ def initialize(*args)
269
+ @stream, @start, @length = args
270
+ @transformed_stream = false
277
271
  end
278
- def method_missing(*a)
279
- unless @str
280
- @str = @s[@f1, @f2].to_s
281
- @s[@f1, @f2] = [nil] * @f2
282
- @str
283
- end
284
- @str.send(*a)
272
+
273
+ if RUBY_VERSION_ID >= 191
274
+ undef_method :to_s, :inspect, :==
275
+ end
276
+
277
+ private
278
+
279
+ def method_missing(*args, &block)
280
+ transform_stream unless transformed_stream?
281
+ @str.__send__(*args, &block)
282
+ end
283
+
284
+ def transform_stream
285
+ @transformed_stream = true
286
+
287
+ # We can't do @stream.slice!(@start, @length),
288
+ # as it would invalidate the @starts and @lengths of other Fragment instances.
289
+ @str = @stream[@start, @length].to_s
290
+ @stream[@start, @length] = [nil] * @length
291
+ end
292
+
293
+ def transformed_stream?
294
+ @transformed_stream
285
295
  end
286
296
  end
287
297
 
298
+ class XmlMarkup < ::Builder::XmlMarkup
299
+ attr_accessor :target, :level
300
+ end
288
301
  end