Skip to content

Instantly share code, notes, and snippets.

@nov
Created June 5, 2009 06:34
Show Gist options
  • Save nov/124110 to your computer and use it in GitHub Desktop.
Save nov/124110 to your computer and use it in GitHub Desktop.
# NOTICE:
# JsonMarkup returns Hash, not Json text.
# You need to call to_json for returned target.
# USAGE
# def to_markup(markup, options = {})
# markup = case format
# when :xml
# Builder::XmlMarkup.new
# when :json
# Builder::JsonMarkup.new
# end
# markup.user(
# :id => id,
# :url => url
# )
# markup.array_mode do
# markup.images do
# package.images.each do |image|
# markup << image.to_markup(format, :only_url => true)
# end
# end
# end
# markup.target!
# end
#
# def to_xml(options = {})
# self.to_markup(:xml, options)
# end
#
# def to_json(options = {})
# self.to_markup(:json, options).to_json
# end
module Builder
class XmlMarkup
def array_mode(&block)
yield(self)
end
end
class JsonMarkup
def initialize(options = {})
# @default_content_key is used in such case: markup.key(value, :attr_key => attr_value)
# in this case, we need some key for value.
@default_content_key = (options[:default_content_key] || :content).to_sym
@include_root = options[:include_root]
@target = {}
@array_mode = false
end
def nil?
false
end
# NOTICE: you have to call this method to use array in json
def array_mode(&block)
@array_mode = true
yield(self)
@array_mode = false
end
def target!
if @include_root
@target
else
@target[@root]
end
end
# Do nothing
def comment!; end
def declare!; end
def instruct!; end
def comment!; end
def <<(_target)
if @array_mode
eval("#{current} ||= []")
eval("#{current} << _target")
else
eval("#{current} ||= {}")
eval("#{current}.merge!(_target)")
end
end
def text!(text)
if eval("#{current}").is_a?(Hash)
eval("#{current}.merge!({@default_content_key => text})")
else
eval("#{current} = text")
end
end
alias_method :cdata!, :text!
def tag!(key, *attrs, &block)
method_missing(key, *args, &block)
end
def method_missing(key, *args, &block)
key = args.first.is_a?(Symbol) ? "#{key}:#{args.shift}".to_sym : key.to_sym
args[0] = {@default_content_key => args[0]} if args.size > 1 && !args[0].is_a?(Hash)
unless @root
root(key, args, &block)
else
children(key, args, &block)
end
self
target!
end
private
def root(root, args, &block)
@root = root
@target[root] = {}
@path = [root]
set_args(args, &block)
yield(self) if block_given?
end
def children(key, args, &block)
@path.push(key)
set_args(args, &block)
@path.pop
end
def set_args(args, &block)
args.each do |arg|
case arg
when Hash
eval("#{current} ||= {}")
eval("#{current}.merge!(_target)")
else
eval("#{current} = arg")
end
end
yield(self) if block_given?
end
def current
"@target[:\"#{@path.join('"][:"')}\"]"
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment