hammer_builder 0.2.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -5,12 +5,9 @@ Fast Ruby xhtml5 renderer
5
5
  ## Links
6
6
 
7
7
  * **Presentation**: <http://hammer.pitr.ch/hammer_builder/presentation/presentation.html>
8
- * Gemcutter: <https://rubygems.org/gems/hammer_builder>
9
8
  * Github: <https://github.com/ruby-hammer/hammer-builder>
10
- * Yardoc: <http://rubydoc.info/github/ruby-hammer/hammer-builder/frames>
9
+ * Yardoc: <http://rubydoc.info/gems/hammer_builder/frames>
11
10
  * Issues: <https://github.com/ruby-hammer/hammer-builder/issues>
12
- * Changelog: <http://hammer.pitr.ch/hammer-builder/file.CHANGELOG.html>
13
- * Gem: [https://rubygems.org/gems/hammer_builder](https://rubygems.org/gems/hammer_builder)
14
11
  * Blog: <http://hammer.pitr.ch/>
15
12
 
16
13
  ## Syntax
@@ -3,7 +3,7 @@ require 'active_support/core_ext/class/attribute'
3
3
  require 'active_support/core_ext/string/inflections'
4
4
 
5
5
  require 'hammer_builder/dynamic_classes'
6
- require 'hammer_builder/strings'
6
+ require 'hammer_builder/strings_injector'
7
7
  require 'hammer_builder/data'
8
8
  require 'hammer_builder/data/html5'
9
9
  require "hammer_builder/pool"
@@ -19,6 +19,27 @@ module HammerBuilder
19
19
  require "hammer_builder/abstract/abstract_single_tag"
20
20
  require "hammer_builder/abstract/abstract_double_tag"
21
21
 
22
+ def self.strings_injector
23
+ @strings_injector ||= StringsInjector.new do
24
+ add :lt, '<'
25
+ add :gt, '>'
26
+ add :slash_lt, '</'
27
+ add :slash_gt, ' />'
28
+ add :dash, '-'
29
+ add :underscore, '_'
30
+ add :space, ' '
31
+ add :spaces, Array.new(300) { |i| (' ' * i).freeze }
32
+ add :newline, "\n"
33
+ add :quote, '"'
34
+ add :eql, '='
35
+ add :eql_quote, self[:eql] + self[:quote]
36
+ add :comment_start, '<!--'
37
+ add :comment_end, '-->'
38
+ add :cdata_start, '<![CDATA['
39
+ add :cdata_end, ']]>'
40
+ end
41
+ end
42
+
22
43
  # << faster then +
23
44
  # yield faster then block.call
24
45
  # accessing ivar and constant is faster then accesing hash or cvar
@@ -58,6 +79,9 @@ module HammerBuilder
58
79
  @_output = ""
59
80
  @_stack = []
60
81
  @_current = nil
82
+
83
+ self.class.strings_injector.inject_to self
84
+
61
85
  # tag classes initialization
62
86
  tags.each do |klass|
63
87
  instance_variable_set(:"@_#{klass}", self.class.dynamic_classes[klass.camelize.to_sym].new(self))
@@ -79,13 +103,13 @@ module HammerBuilder
79
103
  # inserts +comment+
80
104
  def comment(comment)
81
105
  flush
82
- @_output << Strings::COMMENT_START << comment.to_s << Strings::COMMENT_END
106
+ @_output << @_str_comment_start << comment.to_s << @_str_comment_end
83
107
  end
84
108
 
85
109
  # insersts CDATA with +content+
86
110
  def cdata(content)
87
111
  flush
88
- @_output << Strings::CDATA_START << content.to_s << Strings::CDATA_END
112
+ @_output << @_str_cdata_start << content.to_s << @_str_cdata_end
89
113
  end
90
114
 
91
115
  # renders html5 doc type
@@ -120,7 +144,7 @@ module HammerBuilder
120
144
  # @example
121
145
  # HammerBuilder::Formatted.new.go_in('asd') do |string|
122
146
  # div string
123
- # end.to_html! #=> "<div>asd</div>"
147
+ # end.to_html #=> "<div>asd</div>"
124
148
  #
125
149
  def go_in(*variables, &block)
126
150
  instance_exec *variables, &block
@@ -186,13 +210,13 @@ module HammerBuilder
186
210
  def join(collection, glue = nil, &it)
187
211
  # TODO as helper? two block method call #join(collection, &item).with(&glue)
188
212
  glue_block = case glue
189
- when String
190
- lambda { text glue }
191
- when Proc
192
- glue
193
- else
194
- lambda { }
195
- end
213
+ when String
214
+ lambda { text glue }
215
+ when Proc
216
+ glue
217
+ else
218
+ lambda { }
219
+ end
196
220
 
197
221
  collection.each_with_index do |obj, i|
198
222
  glue_block.call() if i > 0
@@ -5,55 +5,53 @@ module HammerBuilder
5
5
  def_class :AbstractDoubleTag, :AbstractTag do ###import
6
6
  nil
7
7
 
8
- # defined by class_eval because there is a error cased by super
9
- # super from singleton method that is defined to multiple classes is not supported;
10
- # this will be fixed in 1.9.3 or later (NotImplementedError)
11
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
12
- # @api private
13
- def initialize(builder)
14
- super
15
- @content = nil
16
- end
8
+ # @api private
9
+ def initialize(builder)
10
+ super
11
+ @content = nil
12
+ end
17
13
 
18
- # allows data-* attributes and id, classes by method_missing
19
- def method_missing(method, *args, &block)
20
- method = method.to_s
21
- if method =~ METHOD_MISSING_REGEXP
22
- if $1
23
- self.rclass.add_attributes Data::Attribute.new(method.to_sym, :string)
24
- self.send method, *args, &block
25
- else
26
- self.content(args[0]) if args[0]
27
- self.__send__($3 == '!' ? :id : :class, $2, &block)
28
- end
14
+ # allows data-* attributes and id, classes by method_missing
15
+ def method_missing(method, *args, &block)
16
+ method = method.to_s
17
+ if method =~ METHOD_MISSING_REGEXP
18
+ if $1
19
+ self.rclass.add_attributes Data::Attribute.new(method.to_sym, :string)
20
+ self.send method, *args, &block
29
21
  else
30
- super(method, *args, &block)
22
+ attributes(if args.last.is_a?(Hash)
23
+ args.pop
24
+ end)
25
+ content args.first
26
+ self.__send__($3 == '!' ? :id : :class, $2.gsub(@_str_underscore, @_str_dash), &block)
31
27
  end
28
+ else
29
+ super(method, *args, &block)
32
30
  end
31
+ end
33
32
 
34
- # @api private
35
- def open(*args, &block)
36
- attributes = if args.last.is_a?(Hash)
37
- args.pop
38
- end
39
- content args[0]
40
- super attributes
41
- @stack << @tag_name
42
- if block
43
- with &block
44
- else
45
- self
46
- end
33
+ # @api private
34
+ def open(*args, &block)
35
+ attributes = if args.last.is_a?(Hash)
36
+ args.pop
37
+ end
38
+ content args[0]
39
+ super attributes
40
+ @stack << @tag_name
41
+ if block
42
+ with &block
43
+ else
44
+ self
47
45
  end
48
- RUBY
46
+ end
49
47
 
50
48
  # @api private
51
49
  # closes the tag
52
50
  def flush
53
51
  flush_classes
54
- @output << Strings::GT
52
+ @output << @_str_gt
55
53
  @output << CGI.escapeHTML(@content) if @content
56
- @output << Strings::SLASH_LT << @stack.pop << Strings::GT
54
+ @output << @_str_slash_lt << @stack.pop << @_str_gt
57
55
  @content = nil
58
56
  end
59
57
 
@@ -76,7 +74,7 @@ module HammerBuilder
76
74
  # end # => <div id="id">content</div>
77
75
  def with
78
76
  flush_classes
79
- @output << Strings::GT
77
+ @output << @_str_gt
80
78
  @content = nil
81
79
  @builder.current = nil
82
80
  yield
@@ -84,37 +82,35 @@ module HammerBuilder
84
82
  # @output << EscapeUtils.escape_html(content)
85
83
  #end
86
84
  @builder.flush
87
- @output << Strings::SLASH_LT << @stack.pop << Strings::GT
85
+ @output << @_str_slash_lt << @stack.pop << @_str_gt
88
86
  nil
89
87
  end
90
88
 
91
89
  alias_method :w, :with
92
90
 
93
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
94
- def mimic(obj, &block)
95
- super(obj, &nil)
96
- return with(&block) if block
97
- self
98
- end
91
+ def mimic(obj, &block)
92
+ super(obj, &nil)
93
+ return with(&block) if block
94
+ self
95
+ end
99
96
 
100
- def data(hash, &block)
101
- super(hash, &nil)
102
- return with(&block) if block
103
- self
104
- end
97
+ def data(hash, &block)
98
+ super(hash, &nil)
99
+ return with(&block) if block
100
+ self
101
+ end
105
102
 
106
- def attribute(name, value, &block)
107
- super(name, value, &nil)
108
- return with(&block) if block
109
- self
110
- end
103
+ def attribute(name, value, &block)
104
+ super(name, value, &nil)
105
+ return with(&block) if block
106
+ self
107
+ end
111
108
 
112
- def attributes(attrs, &block)
113
- super(attrs, &nil)
114
- return with(&block) if block
115
- self
116
- end
117
- RUBY
109
+ def attributes(attrs, &block)
110
+ super(attrs, &nil)
111
+ return with(&block) if block
112
+ self
113
+ end
118
114
 
119
115
  protected
120
116
 
@@ -125,20 +121,20 @@ module HammerBuilder
125
121
 
126
122
  if instance_methods.include?(attribute.name)
127
123
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
128
- def #{name}(*args, &block)
129
- super(*args, &nil)
130
- return with(&block) if block
131
- self
132
- end
124
+ def #{name}(*args, &block)
125
+ super(*args, &nil)
126
+ return with(&block) if block
127
+ self
128
+ end
133
129
  RUBY
134
130
  else
135
131
  content_rendering = attribute_content_rendering(attribute)
136
132
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
137
- def #{name}(content#{' = true' if attribute.type == :boolean}, &block)
138
- #{content_rendering}
139
- return with(&block) if block
140
- self
141
- end
133
+ def #{name}(content#{' = true' if attribute.type == :boolean}, &block)
134
+ #{content_rendering}
135
+ return with(&block) if block
136
+ self
137
+ end
142
138
  RUBY
143
139
  end
144
140
  end
@@ -8,7 +8,7 @@ module HammerBuilder
8
8
  # closes the tag
9
9
  def flush
10
10
  flush_classes
11
- @output << Strings::SLASH_GT
11
+ @output << @_str_slash_gt
12
12
  nil
13
13
  end
14
14
  end ###import
@@ -3,6 +3,10 @@ module HammerBuilder
3
3
  dynamic_classes do
4
4
  def_class :AbstractTag do ###import
5
5
 
6
+ def self.strings_injector
7
+ dynamic_class_base.strings_injector
8
+ end
9
+
6
10
  class_attribute :_attributes, :instance_writer => false, :instance_reader => false
7
11
  self._attributes = []
8
12
 
@@ -58,11 +62,13 @@ module HammerBuilder
58
62
  name = attribute.name.to_s
59
63
  case attribute.type
60
64
  when :string
61
- Strings.add "attr_#{name}", " #{name.gsub('_', '-')}=\""
62
- "@output << Strings::ATTR_#{name.upcase} << CGI.escapeHTML(content.to_s) << Strings::QUOTE"
65
+ strings_injector.add "attr_#{name}", " #{name.gsub('_', '-')}=#{strings_injector[:quote]}"
66
+ "@output << @_str_attr_#{name} << CGI.escapeHTML(content.to_s) << @_str_quote"
63
67
  when :boolean
64
- Strings.add "attr_#{name}", " #{name.gsub('_', '-')}=\"#{name}\""
65
- "@output << Strings::ATTR_#{name.upcase} if content"
68
+ strings_injector.add(
69
+ "attr_#{name}",
70
+ " #{name.gsub('_', '-')}=#{strings_injector[:quote]}#{name}#{strings_injector[:quote]}")
71
+ "@output << @_str_attr_#{name} if content"
66
72
  end
67
73
  end
68
74
 
@@ -87,11 +93,13 @@ module HammerBuilder
87
93
  @stack = builder.instance_eval { @_stack }
88
94
  @classes = []
89
95
  @tag_name = self.rclass.tag_name
96
+
97
+ self.rclass.strings_injector.inject_to self
90
98
  end
91
99
 
92
100
  # @api private
93
101
  def open(attributes = nil)
94
- @output << Strings::LT << @tag_name
102
+ @output << @_str_lt << @tag_name
95
103
  @builder.current = self
96
104
  attributes(attributes)
97
105
  default
@@ -103,7 +111,7 @@ module HammerBuilder
103
111
  # @param [#to_s] value
104
112
  def attribute(name, value)
105
113
  return __send__(name, value) if respond_to?(name)
106
- @output << Strings::SPACE << name.to_s << Strings::EQL_QUOTE << CGI.escapeHTML(value.to_s) << Strings::QUOTE
114
+ @output << @_str_space << name.to_s << @_str_eql_quote << CGI.escapeHTML(value.to_s) << @_str_quote
107
115
  self
108
116
  end
109
117
 
@@ -131,28 +139,27 @@ module HammerBuilder
131
139
  data_attribute = /^data_([a-z_]+)$/
132
140
  METHOD_MISSING_REGEXP = /#{data_attribute}|#{id_class}/ unless defined? METHOD_MISSING_REGEXP
133
141
 
134
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
135
- # allows data-* attributes and id, classes by method_missing
136
- def method_missing(method, *args, &block)
137
- method = method.to_s
138
- if method =~ METHOD_MISSING_REGEXP
139
- if $1
140
- self.rclass.add_attributes Data::Attribute.new(method, :string)
141
- self.send method, *args
142
- else
143
- self.__send__($3 == '!' ? :id : :class, $2)
144
- end
142
+ # allows data-* attributes and id, classes by method_missing
143
+ def method_missing(method, *args, &block)
144
+ method = method.to_s
145
+ if method =~ METHOD_MISSING_REGEXP
146
+ if $1
147
+ self.rclass.add_attributes Data::Attribute.new(method, :string)
148
+ self.send method, *args
145
149
  else
146
- super(method, *args, &block)
150
+ self.__send__($3 == '!' ? :id : :class, $2.gsub(@_str_underscore, @_str_dash))
151
+ self.attributes args.first
147
152
  end
153
+ else
154
+ super(method, *args, &block)
148
155
  end
156
+ end
149
157
 
150
- #def respond_to?(symbol, include_private = false)
151
- # symbol.to_s =~ METHOD_MISSING_REGEXP || super(symbol, include_private)
152
- #end
153
- RUBY
158
+ #def respond_to?(symbol, include_private = false)
159
+ # symbol.to_s =~ METHOD_MISSING_REGEXP || super(symbol, include_private)
160
+ #end
154
161
 
155
- Strings.add "attr_class", " class=\""
162
+ strings_injector.add "attr_class", " class=#{strings_injector[:quote]}"
156
163
  # adds classes to the tag by joining +classes+ with ' ' and skipping non-true classes
157
164
  # @param [Array<#to_s>] classes
158
165
  # @example
@@ -162,14 +169,13 @@ module HammerBuilder
162
169
  self
163
170
  end
164
171
 
165
- Strings.add "attr_id", " id=\""
172
+ strings_injector.add "attr_id", " id=#{strings_injector[:quote]}"
166
173
  # adds id to the tag by joining +values+ with '_'
167
174
  # @param [Array<#to_s>] values
168
175
  # @example
169
- # id('user', 12) #=> id="user_15"
176
+ # id('user', 12) #=> id="user-15"
170
177
  def id(*values)
171
- @output << Strings::ATTR_ID << CGI.escapeHTML(values.select { |v| v }.join(Strings::UNDERSCORE)) <<
172
- Strings::QUOTE
178
+ @output << @_str_attr_id << CGI.escapeHTML(values.select { |v| v }.join(@_str_dash)) << @_str_quote
173
179
  self
174
180
  end
175
181
 
@@ -182,19 +188,19 @@ module HammerBuilder
182
188
  # div[AUser.new].with { text 'a' } # => <div id="a_user_1" class="a_user">a</div>
183
189
  def mimic(obj)
184
190
  klass = if obj.class.respond_to? :hammer_builder_ref
185
- obj.class.hammer_builder_ref
186
- else
187
- ActiveSupport::Inflector.underscore(obj.class.to_s).tr('/', '-')
188
- end
191
+ obj.class.hammer_builder_ref
192
+ else
193
+ ActiveSupport::Inflector.underscore(obj.class.to_s).tr('/', '-')
194
+ end
189
195
 
190
196
  id = case
191
- when obj.respond_to?(:hammer_builder_ref)
192
- obj.hammer_builder_ref
193
- when obj.respond_to?(:id)
194
- [klass, obj.id]
195
- else
196
- [klass, obj.object_id]
197
- end
197
+ when obj.respond_to?(:hammer_builder_ref)
198
+ obj.hammer_builder_ref
199
+ when obj.respond_to?(:id)
200
+ [klass, obj.id]
201
+ else
202
+ [klass, obj.object_id]
203
+ end
198
204
  #noinspection RubyArgCount
199
205
  self.class(klass).id(id)
200
206
  end
@@ -222,7 +228,7 @@ module HammerBuilder
222
228
  # @api private
223
229
  def flush_classes
224
230
  unless @classes.empty?
225
- @output << Strings::ATTR_CLASS << CGI.escapeHTML(@classes.join(Strings::SPACE)) << Strings::QUOTE
231
+ @output << @_str_attr_class << CGI.escapeHTML(@classes.join(@_str_space)) << @_str_quote
226
232
  @classes.clear
227
233
  end
228
234
  end