garterbelt 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +16 -0
  4. data/Gemfile.lock +38 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.rdoc +21 -0
  7. data/Rakefile +46 -0
  8. data/TODO +3 -0
  9. data/VERSION +1 -0
  10. data/garterbelt.gemspec +165 -0
  11. data/lib/garterbelt.rb +23 -0
  12. data/lib/page.rb +46 -0
  13. data/lib/renderers/cache.rb +35 -0
  14. data/lib/renderers/closed_tag.rb +60 -0
  15. data/lib/renderers/comment.rb +14 -0
  16. data/lib/renderers/content_rendering.rb +41 -0
  17. data/lib/renderers/content_tag.rb +36 -0
  18. data/lib/renderers/doctype.rb +24 -0
  19. data/lib/renderers/renderer.rb +33 -0
  20. data/lib/renderers/text.rb +28 -0
  21. data/lib/renderers/xml.rb +9 -0
  22. data/lib/stocking.rb +11 -0
  23. data/lib/support/string.rb +165 -0
  24. data/lib/view.rb +341 -0
  25. data/spec/benchmark/templates/erector.rb +37 -0
  26. data/spec/benchmark/templates/garterbelt.rb +37 -0
  27. data/spec/benchmark/vs_erector.rb +53 -0
  28. data/spec/garterbelt_spec.rb +49 -0
  29. data/spec/integration/expectations/general_view.html +17 -0
  30. data/spec/integration/expectations/variables/view_with_user_and_params.html +23 -0
  31. data/spec/integration/expectations/variables/view_with_user_email.html +23 -0
  32. data/spec/integration/expectations/view_partial_nest.html +24 -0
  33. data/spec/integration/expectations/view_with_tags.html +19 -0
  34. data/spec/integration/templates/view_partial_nest.rb +22 -0
  35. data/spec/integration/templates/view_with_cache.rb +30 -0
  36. data/spec/integration/templates/view_with_partial.rb +36 -0
  37. data/spec/integration/templates/view_with_partial_2.rb +36 -0
  38. data/spec/integration/templates/view_with_tags.rb +26 -0
  39. data/spec/integration/templates/view_with_vars.rb +32 -0
  40. data/spec/integration/view_spec.rb +57 -0
  41. data/spec/page_spec.rb +99 -0
  42. data/spec/renderers/cache_spec.rb +85 -0
  43. data/spec/renderers/closed_tag_spec.rb +172 -0
  44. data/spec/renderers/comment_spec.rb +68 -0
  45. data/spec/renderers/content_tag_spec.rb +150 -0
  46. data/spec/renderers/doctype_spec.rb +46 -0
  47. data/spec/renderers/text_spec.rb +68 -0
  48. data/spec/spec_helper.rb +17 -0
  49. data/spec/support/mock_view.rb +14 -0
  50. data/spec/support/puters.rb +10 -0
  51. data/spec/view/view_basics_spec.rb +106 -0
  52. data/spec/view/view_caching_spec.rb +132 -0
  53. data/spec/view/view_partial_spec.rb +63 -0
  54. data/spec/view/view_rails_type_helpers.rb +148 -0
  55. data/spec/view/view_render_spec.rb +408 -0
  56. data/spec/view/view_variables_spec.rb +159 -0
  57. metadata +367 -0
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'ru_pol', '0.1.2'
4
+ gem 'activesupport', ">=2.3.8"
5
+ gem 'moneta', '>=0.6.0'
6
+
7
+ # Add dependencies to develop your gem here.
8
+ # Include everything needed to run rake, tests, features, etc.
9
+ group :development do
10
+ gem "hashie", "~>1.0"
11
+ gem "rspec", "~> 2.3.0"
12
+ gem "yard", "~> 0.6.0"
13
+ gem "bundler", "~> 1.0.0"
14
+ gem "jeweler", "~> 1.5.2"
15
+ gem "rcov", ">= 0"
16
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,38 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activesupport (3.0.4)
5
+ diff-lcs (1.1.2)
6
+ git (1.2.5)
7
+ hashie (1.0.0)
8
+ jeweler (1.5.2)
9
+ bundler (~> 1.0.0)
10
+ git (>= 1.2.5)
11
+ rake
12
+ moneta (0.6.0)
13
+ rake (0.8.7)
14
+ rcov (0.9.9)
15
+ rspec (2.3.0)
16
+ rspec-core (~> 2.3.0)
17
+ rspec-expectations (~> 2.3.0)
18
+ rspec-mocks (~> 2.3.0)
19
+ rspec-core (2.3.1)
20
+ rspec-expectations (2.3.0)
21
+ diff-lcs (~> 1.1.2)
22
+ rspec-mocks (2.3.0)
23
+ ru_pol (0.1.2)
24
+ yard (0.6.5)
25
+
26
+ PLATFORMS
27
+ ruby
28
+
29
+ DEPENDENCIES
30
+ activesupport (>= 2.3.8)
31
+ bundler (~> 1.0.0)
32
+ hashie (~> 1.0)
33
+ jeweler (~> 1.5.2)
34
+ moneta (>= 0.6.0)
35
+ rcov
36
+ rspec (~> 2.3.0)
37
+ ru_pol (= 0.1.2)
38
+ yard (~> 0.6.0)
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Kane Baccigalupi
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,21 @@
1
+ = garterbelt
2
+
3
+ Garterbelt is a Ruby HTML/XML markup framework inspired by Erector and Markaby. Garterbelt maps html tags to methods allowing the intuitive construction of HTML pages using nothing but Ruby. And because it is all Ruby all the time, views benefit from the dryness of inheritance, modules and all the meta magic that Ruby can imagine. Stockings not included.
4
+
5
+ More docs coming soon!
6
+
7
+ == Contributing to garterbelt
8
+
9
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
10
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
11
+ * Fork the project
12
+ * Start a feature/bugfix branch
13
+ * Commit and push until you are happy with your contribution
14
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
15
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
16
+
17
+ == Copyright
18
+
19
+ Copyright (c) 2011 Kane Baccigalupi. See LICENSE.txt for
20
+ further details.
21
+
data/Rakefile ADDED
@@ -0,0 +1,46 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "garterbelt"
16
+ gem.homepage = "http://github.com/baccigalupi/garterbelt"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{Garterbelt is a Ruby HTML/XML markup framework. It is san DSL. Just all Ruby, all the time.}
19
+ gem.description = %Q{Garterbelt is a Ruby HTML/XML markup framework inspired by Erector and Markaby. Garterbelt maps html tags to methods allowing the intuitive construction of HTML pages using nothing but Ruby. And because it is all Ruby all the time, views benefit from the dryness of inheritance, modules and all the meta magic that Ruby can imagine. Stockings not included.}
20
+ gem.email = "baccigalupi@gmail.com"
21
+ gem.authors = ["Kane Baccigalupi"]
22
+
23
+ gem.add_development_dependency 'hashie', '~>1.0'
24
+ gem.add_development_dependency 'rbench'
25
+
26
+ gem.add_runtime_dependency 'ru_pol', '>=0.1.2'
27
+ gem.add_runtime_dependency 'activesupport', '>=2.3.8'
28
+ gem.add_runtime_dependency 'moneta', '>=0.6.0'
29
+ end
30
+ Jeweler::RubygemsDotOrgTasks.new
31
+
32
+ require 'rspec/core'
33
+ require 'rspec/core/rake_task'
34
+ RSpec::Core::RakeTask.new(:spec) do |spec|
35
+ spec.pattern = FileList['spec/**/*_spec.rb']
36
+ end
37
+
38
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
39
+ spec.pattern = 'spec/**/*_spec.rb'
40
+ spec.rcov = true
41
+ end
42
+
43
+ task :default => :spec
44
+
45
+ require 'yard'
46
+ YARD::Rake::YardocTask.new
data/TODO ADDED
@@ -0,0 +1,3 @@
1
+ Page
2
+
3
+ - partial passes down params from parent view
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.2
@@ -0,0 +1,165 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{garterbelt}
8
+ s.version = "0.0.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Kane Baccigalupi"]
12
+ s.date = %q{2011-04-12}
13
+ s.description = %q{Garterbelt is a Ruby HTML/XML markup framework inspired by Erector and Markaby. Garterbelt maps html tags to methods allowing the intuitive construction of HTML pages using nothing but Ruby. And because it is all Ruby all the time, views benefit from the dryness of inheritance, modules and all the meta magic that Ruby can imagine. Stockings not included.}
14
+ s.email = %q{baccigalupi@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc",
18
+ "TODO"
19
+ ]
20
+ s.files = [
21
+ ".document",
22
+ ".rspec",
23
+ "Gemfile",
24
+ "Gemfile.lock",
25
+ "LICENSE.txt",
26
+ "README.rdoc",
27
+ "Rakefile",
28
+ "TODO",
29
+ "VERSION",
30
+ "garterbelt.gemspec",
31
+ "lib/garterbelt.rb",
32
+ "lib/page.rb",
33
+ "lib/renderers/cache.rb",
34
+ "lib/renderers/closed_tag.rb",
35
+ "lib/renderers/comment.rb",
36
+ "lib/renderers/content_rendering.rb",
37
+ "lib/renderers/content_tag.rb",
38
+ "lib/renderers/doctype.rb",
39
+ "lib/renderers/renderer.rb",
40
+ "lib/renderers/text.rb",
41
+ "lib/renderers/xml.rb",
42
+ "lib/stocking.rb",
43
+ "lib/support/string.rb",
44
+ "lib/view.rb",
45
+ "spec/benchmark/templates/erector.rb",
46
+ "spec/benchmark/templates/garterbelt.rb",
47
+ "spec/benchmark/vs_erector.rb",
48
+ "spec/garterbelt_spec.rb",
49
+ "spec/integration/expectations/general_view.html",
50
+ "spec/integration/expectations/variables/view_with_user_and_params.html",
51
+ "spec/integration/expectations/variables/view_with_user_email.html",
52
+ "spec/integration/expectations/view_partial_nest.html",
53
+ "spec/integration/expectations/view_with_tags.html",
54
+ "spec/integration/templates/view_partial_nest.rb",
55
+ "spec/integration/templates/view_with_cache.rb",
56
+ "spec/integration/templates/view_with_partial.rb",
57
+ "spec/integration/templates/view_with_partial_2.rb",
58
+ "spec/integration/templates/view_with_tags.rb",
59
+ "spec/integration/templates/view_with_vars.rb",
60
+ "spec/integration/view_spec.rb",
61
+ "spec/page_spec.rb",
62
+ "spec/renderers/cache_spec.rb",
63
+ "spec/renderers/closed_tag_spec.rb",
64
+ "spec/renderers/comment_spec.rb",
65
+ "spec/renderers/content_tag_spec.rb",
66
+ "spec/renderers/doctype_spec.rb",
67
+ "spec/renderers/text_spec.rb",
68
+ "spec/spec_helper.rb",
69
+ "spec/support/mock_view.rb",
70
+ "spec/support/puters.rb",
71
+ "spec/view/view_basics_spec.rb",
72
+ "spec/view/view_caching_spec.rb",
73
+ "spec/view/view_partial_spec.rb",
74
+ "spec/view/view_rails_type_helpers.rb",
75
+ "spec/view/view_render_spec.rb",
76
+ "spec/view/view_variables_spec.rb"
77
+ ]
78
+ s.homepage = %q{http://github.com/baccigalupi/garterbelt}
79
+ s.licenses = ["MIT"]
80
+ s.require_paths = ["lib"]
81
+ s.rubygems_version = %q{1.3.7}
82
+ s.summary = %q{Garterbelt is a Ruby HTML/XML markup framework. It is san DSL. Just all Ruby, all the time.}
83
+ s.test_files = [
84
+ "spec/benchmark/templates/erector.rb",
85
+ "spec/benchmark/templates/garterbelt.rb",
86
+ "spec/benchmark/vs_erector.rb",
87
+ "spec/garterbelt_spec.rb",
88
+ "spec/integration/templates/view_partial_nest.rb",
89
+ "spec/integration/templates/view_with_cache.rb",
90
+ "spec/integration/templates/view_with_partial.rb",
91
+ "spec/integration/templates/view_with_partial_2.rb",
92
+ "spec/integration/templates/view_with_tags.rb",
93
+ "spec/integration/templates/view_with_vars.rb",
94
+ "spec/integration/view_spec.rb",
95
+ "spec/page_spec.rb",
96
+ "spec/renderers/cache_spec.rb",
97
+ "spec/renderers/closed_tag_spec.rb",
98
+ "spec/renderers/comment_spec.rb",
99
+ "spec/renderers/content_tag_spec.rb",
100
+ "spec/renderers/doctype_spec.rb",
101
+ "spec/renderers/text_spec.rb",
102
+ "spec/spec_helper.rb",
103
+ "spec/support/mock_view.rb",
104
+ "spec/support/puters.rb",
105
+ "spec/view/view_basics_spec.rb",
106
+ "spec/view/view_caching_spec.rb",
107
+ "spec/view/view_partial_spec.rb",
108
+ "spec/view/view_rails_type_helpers.rb",
109
+ "spec/view/view_render_spec.rb",
110
+ "spec/view/view_variables_spec.rb"
111
+ ]
112
+
113
+ if s.respond_to? :specification_version then
114
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
115
+ s.specification_version = 3
116
+
117
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
118
+ s.add_runtime_dependency(%q<ru_pol>, ["= 0.1.2"])
119
+ s.add_runtime_dependency(%q<activesupport>, [">= 2.3.8"])
120
+ s.add_runtime_dependency(%q<moneta>, [">= 0.6.0"])
121
+ s.add_development_dependency(%q<hashie>, ["~> 1.0"])
122
+ s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
123
+ s.add_development_dependency(%q<yard>, ["~> 0.6.0"])
124
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
125
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
126
+ s.add_development_dependency(%q<rcov>, [">= 0"])
127
+ s.add_development_dependency(%q<hashie>, ["~> 1.0"])
128
+ s.add_development_dependency(%q<rbench>, [">= 0"])
129
+ s.add_runtime_dependency(%q<ru_pol>, [">= 0.1.2"])
130
+ s.add_runtime_dependency(%q<activesupport>, [">= 2.3.8"])
131
+ s.add_runtime_dependency(%q<moneta>, [">= 0.6.0"])
132
+ else
133
+ s.add_dependency(%q<ru_pol>, ["= 0.1.2"])
134
+ s.add_dependency(%q<activesupport>, [">= 2.3.8"])
135
+ s.add_dependency(%q<moneta>, [">= 0.6.0"])
136
+ s.add_dependency(%q<hashie>, ["~> 1.0"])
137
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
138
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
139
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
140
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
141
+ s.add_dependency(%q<rcov>, [">= 0"])
142
+ s.add_dependency(%q<hashie>, ["~> 1.0"])
143
+ s.add_dependency(%q<rbench>, [">= 0"])
144
+ s.add_dependency(%q<ru_pol>, [">= 0.1.2"])
145
+ s.add_dependency(%q<activesupport>, [">= 2.3.8"])
146
+ s.add_dependency(%q<moneta>, [">= 0.6.0"])
147
+ end
148
+ else
149
+ s.add_dependency(%q<ru_pol>, ["= 0.1.2"])
150
+ s.add_dependency(%q<activesupport>, [">= 2.3.8"])
151
+ s.add_dependency(%q<moneta>, [">= 0.6.0"])
152
+ s.add_dependency(%q<hashie>, ["~> 1.0"])
153
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
154
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
155
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
156
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
157
+ s.add_dependency(%q<rcov>, [">= 0"])
158
+ s.add_dependency(%q<hashie>, ["~> 1.0"])
159
+ s.add_dependency(%q<rbench>, [">= 0"])
160
+ s.add_dependency(%q<ru_pol>, [">= 0.1.2"])
161
+ s.add_dependency(%q<activesupport>, [">= 2.3.8"])
162
+ s.add_dependency(%q<moneta>, [">= 0.6.0"])
163
+ end
164
+ end
165
+
data/lib/garterbelt.rb ADDED
@@ -0,0 +1,23 @@
1
+ stocking_dir = File.dirname(__FILE__)
2
+
3
+ require 'active_support/core_ext/string/output_safety'
4
+ require stocking_dir + '/support/string'
5
+
6
+ require 'ru_pol'
7
+ require 'moneta'
8
+ require 'moneta/memory'
9
+
10
+ require stocking_dir + '/stocking'
11
+
12
+ require stocking_dir + '/renderers/renderer'
13
+ require stocking_dir + '/renderers/content_rendering'
14
+ require stocking_dir + '/renderers/closed_tag'
15
+ require stocking_dir + '/renderers/content_tag'
16
+ require stocking_dir + '/renderers/cache'
17
+ require stocking_dir + '/renderers/text'
18
+ require stocking_dir + '/renderers/comment'
19
+ require stocking_dir + '/renderers/doctype'
20
+ require stocking_dir + '/renderers/xml'
21
+
22
+ require stocking_dir + '/view'
23
+ require stocking_dir + '/page'
data/lib/page.rb ADDED
@@ -0,0 +1,46 @@
1
+ module Garterbelt
2
+ class Page < View
3
+ # CLASS LEVEL CONFIGURATION --------------------------------------
4
+
5
+ class << self
6
+ attr_writer :doctype, :html_attributes
7
+ end
8
+
9
+ def self.superclassed?
10
+ superclass.ancestors.include?(Garterbelt::Page)
11
+ end
12
+
13
+ def self.doctype
14
+ @doctype ||= superclassed? ? superclass.doctype : :transitional
15
+ end
16
+
17
+ def self.html_attributes
18
+ @html_attributes ||= superclassed? ? superclass.html_attributes : {}
19
+ end
20
+
21
+ # THE CONTENT ----------------------------------------------------
22
+
23
+ def body_attributes
24
+ {}
25
+ end
26
+
27
+ def content
28
+ doctype self.class.doctype
29
+ html( self.class.html_attributes ) do
30
+ tag(:head) do
31
+ head
32
+ end
33
+
34
+ tag(:body, body_attributes) do
35
+ body
36
+ end
37
+ end
38
+ end
39
+
40
+ def head
41
+ end
42
+
43
+ def body
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,35 @@
1
+ module Garterbelt
2
+ class Cache < Renderer
3
+ include ContentRendering
4
+
5
+ attr_accessor :key, :cache_output, :view_output
6
+
7
+ def initialize(opts, &block)
8
+ super
9
+ self.key = opts[:key]
10
+ raise ArgumentError, ":key option required" unless key
11
+ self.content = block if block_given?
12
+ raise_unless_block_content
13
+ self.cache_output = ""
14
+ end
15
+
16
+ def head
17
+ self.view_output = output
18
+ self.output = cache_output
19
+ end
20
+
21
+ def foot
22
+ view_output << cache_output
23
+ self.output = view_output
24
+ end
25
+
26
+ def render_content
27
+ if cached = view.cache_store[key]
28
+ self.output << cached
29
+ else
30
+ super # renders block to the diverted output
31
+ view.cache_store[key] = cache_output # set the cache
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,60 @@
1
+ module Garterbelt
2
+ class ClosedTag < Renderer
3
+ include RuPol::Swimsuit
4
+ max_pool_size 10000
5
+
6
+ attr_accessor :type, :attributes, :css_class
7
+
8
+ def initialize(opts)
9
+ super
10
+ self.type = opts[:type] || raise(ArgumentError, ":type required in initialization options")
11
+ self.attributes = opts[:attributes] || {}
12
+
13
+ css_class = attributes.delete(:class)
14
+ self.css_class = if css_class
15
+ css_class.is_a?(Array) ? css_class : [css_class]
16
+ else
17
+ []
18
+ end
19
+ end
20
+
21
+ # Convenience method chaining ---------------------------
22
+
23
+ def id(identifier)
24
+ raise ArgumentError, "Id must be a String or Symbol" unless [String, Symbol].include?(identifier.class)
25
+ self.attributes[:id] = identifier
26
+ self
27
+ end
28
+
29
+ def c(*args)
30
+ self.css_class += args
31
+ self
32
+ end
33
+
34
+ # Rendering -----------------------------------------------
35
+
36
+ def rendered_attributes
37
+ str = ""
38
+ str << " class=\"#{css_class.join(' ')}\"" unless css_class.empty?
39
+ keys = attributes.keys.sort{|a, b| a.to_s <=> b.to_s}
40
+ keys.each do |key|
41
+ value = attributes[key]
42
+ if value
43
+ value = value.to_s.gsub('"', '\'')
44
+ str << " #{key}=\"#{value}\""
45
+ end
46
+ end
47
+ str
48
+ end
49
+
50
+ def template
51
+ "#{indent}<#{type}#{rendered_attributes}>\n"
52
+ end
53
+
54
+ def render
55
+ str = template
56
+ self.output << str
57
+ str
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,14 @@
1
+ module Garterbelt
2
+ class Comment < Text
3
+ max_pool_size 1000
4
+
5
+ def initialize(opts)
6
+ super
7
+ end
8
+
9
+ def render
10
+ raise_with_block_content
11
+ output << "#{indent}<!-- #{content} -->\n"
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,41 @@
1
+ module Garterbelt
2
+ module ContentRendering
3
+ def self.included(base)
4
+ base.class_eval <<-RUBY
5
+ attr_accessor :content
6
+
7
+ include InstanceMethods
8
+ RUBY
9
+ end
10
+
11
+ module InstanceMethods
12
+ def render
13
+ head
14
+ render_content
15
+ foot
16
+ output
17
+ end
18
+
19
+ def head
20
+ view.level += 1
21
+ end
22
+
23
+ def foot
24
+ view.level -= 1
25
+ end
26
+
27
+ def render_content
28
+ if content.is_a?(Proc)
29
+ content.call
30
+ else
31
+ view.buffer << Text.new(:view => view, :content => content) if content
32
+ end
33
+ view.render_buffer
34
+ end
35
+
36
+ def raise_unless_block_content
37
+ raise ArgumentError, "Block content required" unless self.content && self.content.is_a?(Proc)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,36 @@
1
+ module Garterbelt
2
+ class ContentTag < ClosedTag
3
+ include ContentRendering
4
+
5
+ def initialize(opts, &block)
6
+ super
7
+ if block_given?
8
+ self.content = block
9
+ else
10
+ self.content = opts[:content]
11
+ end
12
+ end
13
+
14
+ def id(identifier, &block)
15
+ super(identifier)
16
+ self.content = block if block_given?
17
+ self
18
+ end
19
+
20
+ def c(*classes, &block)
21
+ super(*classes)
22
+ self.content = block if block_given?
23
+ self
24
+ end
25
+
26
+ def head
27
+ self.output << "#{indent}<#{type}#{rendered_attributes}>\n"
28
+ super
29
+ end
30
+
31
+ def foot
32
+ super
33
+ self.output << "#{indent}</#{type}>\n"
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,24 @@
1
+ module Garterbelt
2
+ class Doctype < ClosedTag
3
+ max_pool_size 1000
4
+
5
+ ATTRIBUTES = {
6
+ :transitional => "html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"",
7
+ :strict => 'html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"',
8
+ :frameset => 'html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"',
9
+ :html5 => 'html',
10
+ :html1_1 => 'html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"',
11
+ :basic => 'html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd"',
12
+ :mobile => 'html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd"',
13
+ :rdfa => 'html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd"'
14
+ }
15
+
16
+ def rendered_attributes
17
+ ATTRIBUTES[type] || ATTRIBUTES[:transitional]
18
+ end
19
+
20
+ def template
21
+ "#{indent}<!DOCTYPE #{rendered_attributes}>\n"
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,33 @@
1
+ module Garterbelt
2
+ class Renderer
3
+ include RuPol::Swimsuit
4
+ max_pool_size 10000
5
+
6
+ attr_accessor :view
7
+
8
+ def initialize(opts)
9
+ self.view = opts[:view] || raise(ArgumentError, ":view required in initialization options")
10
+ end
11
+
12
+ # Rendering -----------------------------------------------
13
+ def output
14
+ view.output
15
+ end
16
+
17
+ def output=(alt_output)
18
+ view.output = alt_output
19
+ end
20
+
21
+ def level
22
+ view.level
23
+ end
24
+
25
+ def indent
26
+ ' '*level*2
27
+ end
28
+
29
+ def render
30
+ raise NotImplementedError, "Subclasses must implement #render"
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,28 @@
1
+ module Garterbelt
2
+ class Text < Renderer
3
+ attr_accessor :content
4
+
5
+ def initialize(opts)
6
+ super
7
+ raise ArgumentError, ":content option required for #{self.class} initialization" unless opts[:content]
8
+ self.content = opts[:content]
9
+ end
10
+
11
+ def raise_with_block_content
12
+ raise ArgumentError, "#{self.class} does not take block content" if self.content.is_a?(Proc)
13
+ end
14
+
15
+ def render
16
+ raise_with_block_content
17
+ output << "#{indent}#{escaped_content}\n"
18
+ end
19
+
20
+ def escaped_content
21
+ escape? ? ERB::Util.h(content) : content
22
+ end
23
+
24
+ def escape?
25
+ !!view.escape
26
+ end
27
+ end
28
+ end