class Demeler

Constants

MethodsLikeInputText

These calls are effectively generated in the same way as 'text' input tags. Method_missing just does a substitution to implement them.

Attributes

obj[R]
out[R]
usr[R]

Public Class Methods

build(obj=nil, gen_html=false, usr=nil, &block) click to toggle source

The default way to start building your markup. Takes a block and returns the markup.

@param [object] obj a Sequel::Model object, or Hash object with an added 'errors' field. @param [boolean] gen_html A flag to control final output: true=>formatted, false=>compressed. @param [*] usr The usr variable from the caller, although it can be anything because Demeler doesn't use it. @param [Proc] block

# File lib/demeler.rb, line 43
def self.build(obj=nil, gen_html=false, usr=nil, &block)
  demeler = self.new(obj, usr, &block)
  if gen_html then demeler.to_html else demeler.to_s end
end
new(obj=nil, usr=nil, &block) click to toggle source

Demeler.new builds HTML from Ruby code. You can either access out, .to_s or .to_html to return the actual markup.

A note of warning: you'll get extra spaces in textareas if you use .to_html.

@param [object] obj–a Sequel::Model object, or Hash object with an added 'errors' field. @param [*] usr The usr variable from the caller; it can be anything because Demeler doesn't use it. @param [Proc] block

To use this without Sequel, you can use an object like this: class Obj<Hash

attr_accessor :errors
def initialize
  @errors = {}
end

end

# File lib/demeler.rb, line 67
def initialize(obj=nil, usr=nil, &block)
  raise ArgumentError.new("The object passed to Demeler must have an errors field containing a Hash") if obj && !defined?(obj.errors)
  @obj = obj
  @usr = usr
  clear
  instance_eval(&block) if block_given?
end

Public Instance Methods

checkbox(name, opts, values) click to toggle source

The checkbox shortcut

@param [Symbol] name Base Name of the control (numbers 1..n will be added) @param [Hash] opts Attributes for the control @param [Hash] value=>nomenclature pairs

@example

g.checkbox(:vehicle, opts, :volvo=>"Volvo", :saab=>"Saab", :mercedes=>"Mercedes", :audi=>"Audi")

@object [Sequel::Model]

@note: first argument becomes the :name plus a number starting at 1, i.e., “vehicle1”, etc.

# File lib/demeler.rb, line 173
def checkbox(name, opts, values)
  raise ArgumentError.new("In Demeler#checkbox, expected Symbol for argument 1, name") if !name.kind_of?(Symbol)
  raise ArgumentError.new("In Demeler#checkbox, expected Hash for argument 2, opts") if !opts.kind_of?(Hash)
  raise ArgumentError.new("In Demeler#checkbox, expected Hash for argument 3, values") if !values.kind_of?(Hash)
  n = 0
  data = case
  when @obj
    @obj[name]
  when (default = opts.delete(:default))
    default.to_s
  else
    nil
  end
  case data.class.name
  when "String"
    data = data.split(",")
  when "Array"
    # it's alreay in the form we want
  when "Hash"
    data = data.values
  else
    data = nil
  end
  values.each do |value,nomenclature|
    sets = opts.clone
    sets[:name] = "#{name}[#{n+=1}]".to_sym
    sets[:type] = :checkbox
    sets[:value] = value
    sets[:text] = nomenclature
    sets[:checked] = 'true' if data && data.index(value.to_s)
    tag_generator(:input, sets)
  end
end
clear() click to toggle source

Clear out the data in order to start over with the same Demeler obj

# File lib/demeler.rb, line 78
def clear
  @level = 0
  @out = []
  @labels = []
  self
end
method_missing(meth, *args, &block) click to toggle source

Catch tag calls that have not been pre-defined.

@param [String] meth The method that was called. @param [Hash] args Additional arguments passed to the called method. @param [Proc] block.

# File lib/demeler.rb, line 92
def method_missing(meth, *args, &block)
  # This code allows for some input tags that work like <input type="text" ...> to
  # work--for example g.password works in place of g.input(:type=>:password, ...)
  if MethodsLikeInputText.index(meth) # TODO!
    args << {} if !args[-1].kind_of?(Hash)
    args.last[:type] = meth
    meth = :input
  end
  tag_generator(meth, args, &block)
end
p(*args, &block) click to toggle source

Workaround for Kernel#p to make <p /> tags possible.

@param [Hash] args Extra arguments that should be processed before

creating the paragraph tag.

@param [Proc] block

# File lib/demeler.rb, line 110
def p(*args, &block)
  tag_generator(:p, args, &block)
end
radio(name, opts, values) click to toggle source

The radio shortcut

@param [Symbol] name Base Name of the control (numbers 1..n will be added) @param [Hash] opts Attributes for the control @param [Hash] value=>nomenclature pairs

@example

g.radio(:vehicle, {}, :volvo=>"Volvo", :saab=>"Saab", :mercedes=>"Mercedes", :audi=>"Audi")

@note: first argument is the :name; without the name, the radio control won't work

# File lib/demeler.rb, line 219
def radio(name, opts, values)
  raise ArgumentError.new("In Demeler#radio, expected Symbol for argument 1, name") if !name.kind_of?(Symbol)
  raise ArgumentError.new("In Demeler#radio, expected Hash for argument 2, opts") if !opts.kind_of?(Hash)
  raise ArgumentError.new("In Demeler#radio, expected Hash for argument 3, values") if !values.kind_of?(Hash)
  data = case
  when @obj
    @obj[name]
  when (default = opts.delete(:default))
    default.to_s
  else
    nil
  end
  values.each do |value,nomenclature|
    sets = opts.clone
    sets[:name] = "#{name}".to_sym
    sets[:type] = :radio
    sets[:value] = value
    sets[:text] = nomenclature
    sets[:checked] = 'true' if data==value.to_s
    tag_generator(:input, sets)
  end
end
reset(text, opts={}) click to toggle source

The reset shortcut

@param [String] text The text which the button will display @param [Hash] opts Options for the RESET statement

@example

g.reset("Reset", {})
# File lib/demeler.rb, line 251
def reset(text, opts={})
  attr = {:type=>:reset}
  attr[:value] = text
  attr.merge!(opts)
  tag_generator(:input, attr)
end
select(name, args, values) click to toggle source

The select (select_tag) shortcut

@param [Symbol] name The name of the SELECT statement @param [Hash] opts Options for the SELECT statement @param [Hash] values A list of :name=>value pairs the control will have

@example

g.select(:vehicle, {}, :volvo=>"Volvo", :saab=>"Saab", :mercedes=>"Mercedes", :audi=>"Audi")

@note: first argument is the :name=>“vehicle” @note: the second argument is a Hash or nil

# File lib/demeler.rb, line 271
def select(name, args, values)
  raise ArgumentError.new("In Demeler#select, expected Symbol for argument 1, name") if !name.kind_of?(Symbol)
  raise ArgumentError.new("In Demeler#select, expected Hash for argument 2, args") if !args.kind_of?(Hash)
  raise ArgumentError.new("In Demeler#select, expected Hash for argument 3, values") if !values.kind_of?(Hash)
  opts = {:name=>name}.merge(args)
  data = case
  when @obj
    @obj[name]
  when (default = opts.delete(:default))
    default.to_s
  else
    nil
  end
  tag_generator(:select, opts) do
    values.each do |value,nomenclature|
      sets = {:value=>value}
      sets[:selected] = 'true' if data.to_s==value.to_s
      sets[:text] = nomenclature
      tag_generator(:option, [sets])
    end
  end
end
submit(text, opts={}) click to toggle source

The submit shortcut

@param [String] text The text which the button will display @param [Hash] opts Options for the SUBMIT statement

@example

g.submit("Accept Changes", {})
# File lib/demeler.rb, line 303
def submit(text, opts={})
  attr = {:type=>:submit}
  attr[:value] = text
  attr.merge!(opts)
  tag_generator(:input, attr)
end
tag_generator(meth, args=[]) { || ... } click to toggle source

The tag_generator method

@param [Symbol] meth The type of control to be generated @param [Hash] args Options for the tag being generated @param [Proc] block A block which will be called to get input or nest tags

@note The :text option will insert text between the opening and closing tag;

It's useful to create one-line tags with text inserted.
# File lib/demeler.rb, line 320
def tag_generator(meth, args=[], &block)
  # this check catches a loop before it bombs the Demeler class
  raise StandardError.new("looping on #{meth.inspect}, @out=#{@out.inspect}") if (@level += 1)>500

  # This part examines the variations in possible inputs,
  # and rearranges them to suit tag_generator
  case
  when args.kind_of?(Hash)
    # args is a hash (attributes only)
    attr = args
  when args.size==0
    # args is empty array
    attr = {}
  when args.size==1 && args[0].kind_of?(String)
    # args is array of 1 string
    attr = {:text=>args[0]}
  when args.size==1 && args[0].kind_of?(Symbol)
    # args is array of 1 symbol (used as 'name')
    attr = {:name=>args[0]}
  when args.size==1 && args[0].kind_of?(Hash)
    # args is array of 1 hash (same as args is a hash)
    attr = args[0]
  when args.size==2 && args[0].kind_of?(Symbol) && args[1].kind_of?(Hash)
    # args is an array of symbol ('name') and hash ('attributes')
    # both name and attributes, i.e., g.div(:list, :class=>'list-class')
    attr = {:name=>args[0]}.merge(args[1])
  when args.size==2 && args[0].kind_of?(Symbol) && args[1].kind_of?(String)
    # args is array of symbol ('name') and string ('text')
    # both name and text, i.e., g.label(:list, "List")
    case meth
    when :label
      attr = {:for=>args[0]}.merge({:text=>args[1]})
      @labels << args[0]
    else
      attr = {:name=>args[0]}.merge({:text=>args[1]})
    end
  else
    raise ArgumentError.new("Too many arguments in Demeler#tag_generator: meth=>#{meth.inspect}, args=>#{args.inspect}")
  end

  # This part extracts a value out of the form's object (if any)
  name = attr[:name]
  case
  when name.nil?
  when @obj.nil?
  when !attr[:value].nil?
  when @obj[name].nil?
  when @obj[name].kind_of?(String) && @obj[name].empty?
  when meth==:textarea
    attr[:text] = @obj[name] if !attr.has_key?(:text)
  else
    attr[:value] = @obj[name] if !attr.has_key?(:value)
  end

  # If a label was previously defined for this :input,
  # add an :id attribute automatically
  attr[:id] = name if meth==:input && !attr.has_key?(:id) && @labels.index(name)

  # This part extracts the text (if any)--the text
  # is used in place of a block for tags like 'label'
  text = attr.delete(:text)
  case
  when text.nil?
    text = []
  when text.kind_of?(String)
    text = [text]
  when text.kind_of?(Array)
  else
    raise ArgumentError.new("In Demeler#tag_generator, expected Array or String for text (value for textarea, or ")
  end

  # make sure there's at least one (empty) string for textarea because
  # a textarea tag with no "block" makes the browser act wierd, even if it's
  # self-closing, i.e., <textarea ... />
  text = [""] if meth==:textarea && text.empty? && !block_given?

  # In case there is an error message for this field,
  # prepare the message now to add following the field
  if @obj && (list = @obj.errors[name])
    raise ArgumentError.new("The error message, if any, must be an array of Strings") if !list.kind_of?(Array)
    error = if [:input, :select].index(meth) then list.first else nil end
    message = if error then "<warn> <-- #{error}</warn>" else nil end
  else
    message = ""
  end

  # This is where the actual HTML is generated--it's structured this
  # way to be sure that only WHOLE tags are placed into @out--it's
  # done this way to facilitate #to_html
  case
  when !text.empty?
    temp = text.join("\n")
    @out << "<#{meth}#{attr.map{|k,v| %[ #{k}="#{v}"]}.join}>#{temp}</#{meth}>#{message}"
  when block_given?
    @out << "<#{meth}#{attr.map{|k,v| %[ #{k}="#{v}"]}.join}>"
    temp = yield
    @out << temp if temp && temp.kind_of?(String)
    @out << "</#{meth}>#{message}"
  else
    @out << "<#{meth}#{attr.map{|k,v| %[ #{k}="#{v}"]}.join} />#{message}"
  end

  @level -= 1
  nil
end
to_html() click to toggle source

Method for converting the results of Demeler to a human readable string. This isn't recommended for production because it requires much more time to generate the HTML output than to_s.

@return [String] The formatted form output

# File lib/demeler.rb, line 444
def to_html
  # output the segments, but adjust the indentation
  indent = 0
  html = "<!-- begin generated output -->\n"
  @out.each do |part|
    case
    when part =~ /^<\/.*>$/
      indent -= 1
      html << write_html(indent,part)
    when part =~ /^<.*<\/.*>$/
      html << write_html(indent,part)
    when part =~ /^<.*\/>$/
      html << write_html(indent,part)
    when part =~ /^<.*>$/
      html << write_html(indent,part)
      indent += 1
    else
      html << write_html(indent,part)
    end
  end
  # return the formatted string
  html << "<!-- end generated output -->\n"
  return html
end
to_s() click to toggle source

Convert the final output of Demeler to a string. This method has the following alias: “to_str”.

@return [String]

# File lib/demeler.rb, line 432
def to_s
  @out.join
end

Private Instance Methods

write_html(indent,part) click to toggle source

This method is part of to_html.

# File lib/demeler.rb, line 474
  def write_html(indent,part)
#    "<!-- #{indent} --> #{' '*(if indent<0 then 0 else indent end)}#{part}\n"
    "#{' '*(if indent<0 then 0 else indent end)}#{part}\n"
  end