# 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