Class: Wunderbar::XmlMarkup

Inherits:
BuilderClass show all
Defined in:
lib/wunderbar/builder.rb

Instance Method Summary collapse

Methods inherited from BuilderClass

#websocket

Methods inherited from BuilderBase

#get_binding, #set_variables_from_params

Constructor Details

#initialize(args) ⇒ XmlMarkup

Returns a new instance of XmlMarkup.



107
108
109
110
111
# File 'lib/wunderbar/builder.rb', line 107

def initialize(args)
  @_scope = args.delete(:scope)
  @_builder = SpacedMarkup.new(args)
  @_pdf = false
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object

forward to Wunderbar, XmlMarkup, or @_scope



114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/wunderbar/builder.rb', line 114

def method_missing(method, *args, &block)
  if Wunderbar.respond_to? method
    Wunderbar.send method, *args, &block
  elsif SpacedMarkup.public_instance_methods.include? method
    @_builder.__send__ method, *args, &block
  elsif SpacedMarkup.public_instance_methods.include? method.to_s
    @_builder.__send__ method, *args, &block
  elsif @_scope and @_scope.respond_to? method
    @_scope.send method, *args, &block
  else
    super
  end
end

Instance Method Details

#<<(data) ⇒ Object

insert verbatim



274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
# File 'lib/wunderbar/builder.rb', line 274

def <<(data)
  if not String === data or data.include? '<' or data.include? '&'
    require 'nokogiri'
    data = Nokogiri::HTML::fragment(data.to_s).to_xml
  end

  # fix CDATA in most cases (notably scripts)
  data.gsub!(/<!\[CDATA\[(.*?)\]\]>/m) do |cdata|
    if $1.include? '<' or $1.include? '&'
      "//<![CDATA[\n#{$1}\n//]]>"
    else
      $1
    end
  end

  # fix CDATA for style elements
  data.gsub!(/<style([^>])*>\/\/<!\[CDATA\[\n(.*?)\s+\/\/\]\]>/m) do |cdata|
    if $2.include? '<' or $2.include? '&'
      "<style#{$1}>/*<![CDATA[*/\n#{$2.gsub("\n\Z",'')}\n/*]]>*/"
    else
      $1
    end
  end

  @_builder << data
rescue LoadError
  @_builder << data
end

#[](*children) ⇒ Object



303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
# File 'lib/wunderbar/builder.rb', line 303

def [](*children)
  if children.length == 1 and children.first.respond_to? :root
    children = [children.first.root]
  end

  # remove leading and trailing space
  if children.first.text? and children.first.text.strip.empty?
    children.shift
  end

  if not children.empty?
    children.pop if children.last.text? and children.last.text.strip.empty?
  end

  children.each do |child|
    if child.text? or child.cdata?
      text = child.text
      if text.strip.empty?
        text! "\n" if text.count("\n")>1
      elsif indentation_state!.first == 0
        indented_text! text
      else
        indented_text! text.strip
      end
    elsif child.comment?
      comment! child.text.sub(/\A /,'').sub(/ \Z/, '')
    elsif HtmlMarkup.flatten? child.children
      block_element = Proc.new do |node| 
        node.element? and HtmlMarkup::HTML5_BLOCK.include?(node.name)
      end

      if child.children.any?(&block_element)
        # indent children, but disable indentation on consecutive
        # sequences of non-block-elements.  Put another way: break
        # out block elements to a new line.
        tag!(child) do
          children = child.children.to_a
          while not children.empty?
            stop = children.index(&block_element)
            if stop == 0
              self[children.shift]
            else
              disable_indentation! do
                self[*children.shift(stop || children.length)]
              end
            end
          end
        end
      else
        # disable indentation on the entire element
        disable_indentation! do
          tag!(child) {self[*child.children]}
        end
      end
    elsif child.children.empty? and HtmlMarkup::VOID.include? child.name
      tag!(child)
    elsif child.children.all?(&:text?)
      tag!(child, child.text.strip)
    elsif child.children.any?(&:cdata?) and child.text =~ /[<&]/
      self << child
    else
      tag!(child) {self[*child.children]}
    end
  end
end

#comment(*args) ⇒ Object

comment



269
270
271
# File 'lib/wunderbar/builder.rb', line 269

def comment(*args)
  @_builder.comment! *args
end

#declare(*args) ⇒ Object

declaration (DOCTYPE, etc)



264
265
266
# File 'lib/wunderbar/builder.rb', line 264

def declare(*args)
  @_builder.declare!(*args)
end

#methodsObject



128
129
130
131
132
133
# File 'lib/wunderbar/builder.rb', line 128

def methods
  result = super + Wunderbar.methods
  result += SpacedMarkup.public_instance_methods
  result += @_scope.methods if @_scope
  result.uniq
end

#pdf=(value) ⇒ Object



180
181
182
# File 'lib/wunderbar/builder.rb', line 180

def pdf=(value)
  @_pdf = value
end

#pdf?Boolean

Returns:

  • (Boolean)


184
185
186
# File 'lib/wunderbar/builder.rb', line 184

def pdf?
  @_pdf
end

#proxiable_tag!(sym, *args, &block) ⇒ Object



172
173
174
175
176
177
178
# File 'lib/wunderbar/builder.rb', line 172

def proxiable_tag!(sym, *args, &block)
  if block
    tag!(sym, *args, &block)
  else
    CssProxy.new(@_builder, @_builder.target!, sym, args)
  end
end

#respond_to?(method) ⇒ Boolean

Returns:

  • (Boolean)


135
136
137
138
139
140
141
# File 'lib/wunderbar/builder.rb', line 135

def respond_to?(method)
  respond true if Wunderbar.respond_to? method
  respond true if SpacedMarkup.public_instance_methods.include? method
  respond true if SpacedMarkup.public_instance_methods.include?  method.to_s
  respond true if @_scope and @_scope.respond_to? method?
  super
end

#system(command, opts = {}) ⇒ Object

execute a system command, echoing stdin, stdout, and stderr



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/wunderbar/builder.rb', line 189

def system(command, opts={})
  if command.respond_to? :flatten
    flat = command.flatten
    secret = command - flat
    begin
      # if available, use escape as it does prettier quoting
      require 'escape'
      echo = Escape.shell_command(command.compact - secret)
      command = Escape.shell_command(flat.compact).untaint
    rescue LoadError
      # std-lib function that gets the job done
      require 'shellwords'
      echo = Shellwords.join(command.compact - secret)
      command = Shellwords.join(flat.compact).untaint
    end
  else
    echo = command
  end
  
  patterns = opts[:hilite] || []
  patterns=[patterns] if String === patterns or Regexp === patterns
  patterns.map! do |pattern| 
    String === pattern ? Regexp.new(Regexp.escape(pattern)) : pattern
  end

  require 'open3'
  tag  = opts[:tag]  || 'pre'
  output_class = opts[:class] || {}
  stdin  = output_class[:stdin]  || '_stdin'
  stdout = output_class[:stdout] || '_stdout'
  stderr = output_class[:stderr] || '_stderr'
  hilite = output_class[:hilite] || '_stdout _hilite'

  @_builder.tag! tag, echo, :class=>stdin unless opts[:echo] == false

  require 'thread'
  semaphore = Mutex.new
  Open3.popen3(command) do |pin, pout, perr|
    [
      Thread.new do
        until pout.eof?
          out_line = pout.readline.chomp
          semaphore.synchronize do
            if patterns.any? {|pattern| out_line =~ pattern}
              @_builder.tag! tag, out_line, :class=>hilite
            else
              @_builder.tag! tag, out_line, :class=>stdout
            end
          end
        end
      end,

      Thread.new do
        until perr.eof?
          err_line = perr.readline.chomp
          semaphore.synchronize do 
            @_builder.tag! tag, err_line, :class=>stderr
          end
        end
      end,

      Thread.new do
        if opts[:stdin].respond_to? :read
          require 'fileutils'
          FileUtils.copy_stream opts[:stdin], pin
        elsif opts[:stdin]
          pin.write opts[:stdin].to_s
        end
        pin.close
      end
    ].each {|thread| thread.join}
  end
end

#tag!(sym, *args, &block) ⇒ Object

avoid method_missing overhead for the most common case



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/wunderbar/builder.rb', line 144

def tag!(sym, *args, &block)
  if sym.respond_to? :children
    node = sym
    attributes = node.attributes
    if node.attribute_nodes.any?(&:namespace)
      attributes = Hash[node.attribute_nodes.map { |attr| 
        name = attr.name
        name = "#{attr.namespace.prefix}:#{name}" if attr.namespace
        [name, attr.value]
      }]
    end
    attributes.merge!(node.namespaces) if node.namespaces
    args.push attributes
    if node.namespace and node.namespace.prefix
      args.unshift node.name.to_sym
      sym = node.namespace.prefix
    else
      sym = node.name
    end
  end

  if !block and (args.empty? or args == [''])
    CssProxy.new(@_builder, @_builder.target!, sym, args)
  else
    @_builder.tag! sym, *args, &block
  end
end