json_builder 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/blankslate.rb ADDED
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env ruby
2
+ #--
3
+ # Copyright 2004, 2006 by Jim Weirich (jim@weirichhouse.org).
4
+ # All rights reserved.
5
+
6
+ # Permission is granted for use, copying, modification, distribution,
7
+ # and distribution of modified versions of this work as long as the
8
+ # above copyright notice is included.
9
+ #++
10
+
11
+ ######################################################################
12
+ # BlankSlate provides an abstract base class with no predefined
13
+ # methods (except for <tt>\_\_send__</tt> and <tt>\_\_id__</tt>).
14
+ # BlankSlate is useful as a base class when writing classes that
15
+ # depend upon <tt>method_missing</tt> (e.g. dynamic proxies).
16
+ #
17
+ class BlankSlate
18
+ class << self
19
+
20
+ # Hide the method named +name+ in the BlankSlate class. Don't
21
+ # hide +instance_eval+ or any method beginning with "__".
22
+ def hide(name)
23
+ if instance_methods.include?(name.to_s) and
24
+ name !~ /^(__|instance_eval)/
25
+ @hidden_methods ||= {}
26
+ @hidden_methods[name.to_sym] = instance_method(name)
27
+ undef_method name
28
+ end
29
+ end
30
+
31
+ def find_hidden_method(name)
32
+ @hidden_methods ||= {}
33
+ @hidden_methods[name] || superclass.find_hidden_method(name)
34
+ end
35
+
36
+ # Redefine a previously hidden method so that it may be called on a blank
37
+ # slate object.
38
+ def reveal(name)
39
+ hidden_method = find_hidden_method(name)
40
+ fail "Don't know how to reveal method '#{name}'" unless hidden_method
41
+ define_method(name, hidden_method)
42
+ end
43
+ end
44
+
45
+ instance_methods.each { |m| hide(m) }
46
+ end
47
+
48
+ ######################################################################
49
+ # Since Ruby is very dynamic, methods added to the ancestors of
50
+ # BlankSlate <em>after BlankSlate is defined</em> will show up in the
51
+ # list of available BlankSlate methods. We handle this by defining a
52
+ # hook in the Object and Kernel classes that will hide any method
53
+ # defined after BlankSlate has been loaded.
54
+ #
55
+ module Kernel
56
+ class << self
57
+ alias_method :blank_slate_method_added, :method_added
58
+
59
+ # Detect method additions to Kernel and remove them in the
60
+ # BlankSlate class.
61
+ def method_added(name)
62
+ result = blank_slate_method_added(name)
63
+ return result if self != Kernel
64
+ BlankSlate.hide(name)
65
+ result
66
+ end
67
+ end
68
+ end
69
+
70
+ ######################################################################
71
+ # Same as above, except in Object.
72
+ #
73
+ class Object
74
+ class << self
75
+ alias_method :blank_slate_method_added, :method_added
76
+
77
+ # Detect method additions to Object and remove them in the
78
+ # BlankSlate class.
79
+ def method_added(name)
80
+ result = blank_slate_method_added(name)
81
+ return result if self != Object
82
+ BlankSlate.hide(name)
83
+ result
84
+ end
85
+
86
+ def find_hidden_method(name)
87
+ nil
88
+ end
89
+ end
90
+ end
91
+
92
+ ######################################################################
93
+ # Also, modules included into Object need to be scanned and have their
94
+ # instance methods removed from blank slate. In theory, modules
95
+ # included into Kernel would have to be removed as well, but a
96
+ # "feature" of Ruby prevents late includes into modules from being
97
+ # exposed in the first place.
98
+ #
99
+ class Module
100
+ alias blankslate_original_append_features append_features
101
+ def append_features(mod)
102
+ result = blankslate_original_append_features(mod)
103
+ return result if mod != Object
104
+ instance_methods.each do |name|
105
+ BlankSlate.hide(name)
106
+ end
107
+ result
108
+ end
109
+ end
@@ -0,0 +1,7 @@
1
+ require 'json_builder/jsonmarkup'
2
+ require 'json_builder/jsonevents'
3
+
4
+ unless defined?(Rails)
5
+ require 'rubygems'
6
+ require 'json'
7
+ end
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+ #--
3
+ # Copyright 2004, 2006 by Jim Weirich (jim@weirichhouse.org).
4
+ # All rights reserved.
5
+
6
+ # Permission is granted for use, copying, modification, distribution,
7
+ # and distribution of modified versions of this work as long as the
8
+ # above copyright notice is included.
9
+ #++
10
+
11
+ require 'blankslate'
12
+
13
+ ######################################################################
14
+ # BlankSlate has been promoted to a top level name and is now
15
+ # available as a standalone gem. We make the name available in the
16
+ # Builder namespace for compatibility.
17
+ #
18
+ unless defined?(Builder)
19
+ module JsonBuilder
20
+ BlankSlate = ::BlankSlate
21
+ end
22
+ end
@@ -0,0 +1,131 @@
1
+ require 'json_builder/blankslate'
2
+
3
+ module JsonBuilder
4
+
5
+ # Generic error for builder
6
+ class IllegalBlockError < RuntimeError; end
7
+
8
+ # JsonBase is a base class for building XML builders. See
9
+ # JsonBuilder::JsonMarkup and JsonBuilder::JsonEvents for examples.
10
+ class JsonBase < BlankSlate
11
+
12
+ # Create an XML markup builder.
13
+ #
14
+ # out:: Object receiving the markup. +out+ must respond to
15
+ # <tt><<</tt>.
16
+ # indent:: Number of spaces used for indentation (0 implies no
17
+ # indentation and no line breaks).
18
+ # initial:: Level of initial indentation.
19
+ # encoding:: When <tt>encoding</tt> and $KCODE are set to 'utf-8'
20
+ # characters aren't converted to character entities in
21
+ # the output stream.
22
+ def initialize(encoding='utf-8')
23
+ @encoding = encoding.downcase
24
+ end
25
+
26
+ # Create a tag named +sym+. Other than the first argument which
27
+ # is the tag name, the arguments are the same as the tags
28
+ # implemented via <tt>method_missing</tt>.
29
+ def tag!(sym, *args, &block)
30
+ method_missing(sym.to_sym, args, &block)
31
+ end
32
+
33
+ # Create XML markup based on the name of the method. This method
34
+ # is never invoked directly, but is called for each markup method
35
+ # in the markup block.
36
+ def method_missing(sym, *args, &block)
37
+ text = nil
38
+ sym = "#{sym}:#{args.shift}" if args.first.kind_of?(Symbol)
39
+
40
+ @target = '{' if @target.length == 0
41
+ @target.chop! if @target.last == '}'
42
+
43
+ args.each do |arg|
44
+ case arg
45
+ when Hash
46
+ attrs ||= {}
47
+ attrs.merge!(arg)
48
+ else
49
+ text = arg
50
+ end
51
+ end
52
+
53
+ if block
54
+ raise ArgumentError, "JsonMarkup cannot mix a text argument with a block" unless text.nil?
55
+
56
+ _start_tag(sym)
57
+ block.call(self)
58
+ _end_tag
59
+ elsif text.nil?
60
+ _start_tag(sym)
61
+ else
62
+ _start_attr(sym)
63
+ text! text
64
+ _end_tag
65
+ end
66
+
67
+ @target.gsub(/,(\}+)$/, '\1')
68
+ end
69
+
70
+ # Append text to the output target. Escape any markup. May be
71
+ # used within the markup brackets as:
72
+ #
73
+ # builder.p { |b| b.br; b.text! "HI" } #=> <p><br/>HI</p>
74
+ def text!(text)
75
+ value = case text
76
+ when TrueClass then 'true'
77
+ when FalseClass then 'false'
78
+ when NilClass then 'undefined'
79
+ when Float then text.to_s
80
+ when Fixnum then text.to_s
81
+ else "\"#{_escape(text)}\""
82
+ end
83
+
84
+ _text(value)
85
+ end
86
+
87
+ # Append text to the output target without escaping any markup.
88
+ # May be used within the markup brackets as:
89
+ #
90
+ # builder.p { |x| x << "<br/>HI" } #=> <p><br/>HI</p>
91
+ #
92
+ # This is useful when using non-builder enabled software that
93
+ # generates strings. Just insert the string directly into the
94
+ # builder without changing the inserted markup.
95
+ #
96
+ # It is also useful for stacking builder objects. Builders only
97
+ # use <tt><<</tt> to append to the target, so by supporting this
98
+ # method/operation builders can use other builders as their
99
+ # targets.
100
+ def <<(text)
101
+ _text(text)
102
+ end
103
+
104
+ # For some reason, nil? is sent to the JsonMarkup object. If nil?
105
+ # is not defined and method_missing is invoked, some strange kind
106
+ # of recursion happens. Since nil? won't ever be an XML tag, it
107
+ # is pretty safe to define it here. (Note: this is an example of
108
+ # cargo cult programming,
109
+ # cf. http://fishbowl.pastiche.org/2004/10/13/cargo_cult_programming).
110
+ def nil?
111
+ false
112
+ end
113
+
114
+ private
115
+
116
+ require 'json_builder/xchar'
117
+ def _escape(text)
118
+ text.to_xs((@encoding != 'utf-8' or $KCODE != 'UTF8'))
119
+ rescue NoMethodError
120
+ text
121
+ end
122
+
123
+ def _escape_quote(text)
124
+ _escape(text).gsub(%r{"}, '&quot;') # " WART
125
+ end
126
+
127
+ def _newline
128
+ text! "\n"
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,52 @@
1
+ require 'json_builder/jsonmarkup'
2
+
3
+ module JsonBuilder
4
+
5
+ # Create a series of SAX-like XML events (e.g. start_tag, end_tag)
6
+ # from the markup code. XmlEvent objects are used in a way similar
7
+ # to JsonMarkup objects, except that a series of events are generated
8
+ # and passed to a handler rather than generating character-based
9
+ # markup.
10
+ #
11
+ # Usage:
12
+ # xe = JsonBuilder::JsonEvents.new(hander)
13
+ # xe.title("HI") # Sends start_tag/end_tag/text messages to the handler.
14
+ #
15
+ # Indentation may also be selected by providing value for the
16
+ # indentation size and initial indentation level.
17
+ #
18
+ # xe = JsonBuilder::JsonEvents.new(handler, indent_size, initial_indent_level)
19
+ #
20
+ # == XML Event Handler
21
+ #
22
+ # The handler object must expect the following events.
23
+ #
24
+ # [<tt>start_tag(tag, attrs)</tt>]
25
+ # Announces that a new tag has been found. +tag+ is the name of
26
+ # the tag and +attrs+ is a hash of attributes for the tag.
27
+ #
28
+ # [<tt>end_tag(tag)</tt>]
29
+ # Announces that an end tag for +tag+ has been found.
30
+ #
31
+ # [<tt>text(text)</tt>]
32
+ # Announces that a string of characters (+text+) has been found.
33
+ # A series of characters may be broken up into more than one
34
+ # +text+ call, so the client cannot assume that a single
35
+ # callback contains all the text data.
36
+ #
37
+ class JsonEvents < JsonMarkup
38
+ def text!(text)
39
+ @target.text(text)
40
+ end
41
+
42
+ def _start_tag(sym, attrs)
43
+ @target.start_tag(sym, attrs)
44
+ _end_tag
45
+ end
46
+
47
+ def _end_tag
48
+ @target.end_tag
49
+ end
50
+ end
51
+
52
+ end
@@ -0,0 +1,229 @@
1
+ require 'json_builder/jsonbase'
2
+
3
+ module JsonBuilder
4
+
5
+ # Create XML markup easily. All (well, almost all) methods sent to
6
+ # an JsonMarkup object will be translated to the equivalent XML
7
+ # markup. Any method with a block will be treated as an XML markup
8
+ # tag with nested markup in the block.
9
+ #
10
+ # Examples will demonstrate this easier than words. In the
11
+ # following, +xm+ is an +JsonMarkup+ object.
12
+ #
13
+ # xm.em("emphasized") # => <em>emphasized</em>
14
+ # xm.em { xm.b("emp & bold") } # => <em><b>emph &amp; bold</b></em>
15
+ # xm.a("A Link", "href"=>"http://onestepback.org")
16
+ # # => <a href="http://onestepback.org">A Link</a>
17
+ # xm.div { xm.br } # => <div><br/></div>
18
+ # xm.target("name"=>"compile", "option"=>"fast")
19
+ # # => <target option="fast" name="compile"\>
20
+ # # NOTE: order of attributes is not specified.
21
+ #
22
+ # xm.instruct! # <?xml version="1.0" encoding="UTF-8"?>
23
+ # xm.html { # <html>
24
+ # xm.head { # <head>
25
+ # xm.title("History") # <title>History</title>
26
+ # } # </head>
27
+ # xm.body { # <body>
28
+ # xm.comment! "HI" # <!-- HI -->
29
+ # xm.h1("Header") # <h1>Header</h1>
30
+ # xm.p("paragraph") # <p>paragraph</p>
31
+ # } # </body>
32
+ # } # </html>
33
+ #
34
+ # == Notes:
35
+ #
36
+ # * The order that attributes are inserted in markup tags is
37
+ # undefined.
38
+ #
39
+ # * Sometimes you wish to insert text without enclosing tags. Use
40
+ # the <tt>text!</tt> method to accomplish this.
41
+ #
42
+ # Example:
43
+ #
44
+ # xm.div { # <div>
45
+ # xm.text! "line"; xm.br # line<br/>
46
+ # xm.text! "another line"; xmbr # another line<br/>
47
+ # } # </div>
48
+ #
49
+ # * The special XML characters <, >, and & are converted to &lt;,
50
+ # &gt; and &amp; automatically. Use the <tt><<</tt> operation to
51
+ # insert text without modification.
52
+ #
53
+ # * Sometimes tags use special characters not allowed in ruby
54
+ # identifiers. Use the <tt>tag!</tt> method to handle these
55
+ # cases.
56
+ #
57
+ # Example:
58
+ #
59
+ # xml.tag!("SOAP:Envelope") { ... }
60
+ #
61
+ # will produce ...
62
+ #
63
+ # <SOAP:Envelope> ... </SOAP:Envelope>"
64
+ #
65
+ # <tt>tag!</tt> will also take text and attribute arguments (after
66
+ # the tag name) like normal markup methods. (But see the next
67
+ # bullet item for a better way to handle XML namespaces).
68
+ #
69
+ # * Direct support for XML namespaces is now available. If the
70
+ # first argument to a tag call is a symbol, it will be joined to
71
+ # the tag to produce a namespace:tag combination. It is easier to
72
+ # show this than describe it.
73
+ #
74
+ # xml.SOAP :Envelope do ... end
75
+ #
76
+ # Just put a space before the colon in a namespace to produce the
77
+ # right form for builder (e.g. "<tt>SOAP:Envelope</tt>" =>
78
+ # "<tt>xml.SOAP :Envelope</tt>")
79
+ #
80
+ # * JsonMarkup builds the markup in any object (called a _target_)
81
+ # that accepts the <tt><<</tt> method. If no target is given,
82
+ # then JsonMarkup defaults to a string target.
83
+ #
84
+ # Examples:
85
+ #
86
+ # xm = JsonBuilder::JsonMarkup.new
87
+ # result = xm.title("yada")
88
+ # # result is a string containing the markup.
89
+ #
90
+ # buffer = ""
91
+ # xm = JsonBuilder::JsonMarkup.new(buffer)
92
+ # # The markup is appended to buffer (using <<)
93
+ #
94
+ # xm = JsonBuilder::JsonMarkup.new(STDOUT)
95
+ # # The markup is written to STDOUT (using <<)
96
+ #
97
+ # xm = JsonBuilder::JsonMarkup.new
98
+ # x2 = JsonBuilder::JsonMarkup.new(:target=>xm)
99
+ # # Markup written to +x2+ will be send to +xm+.
100
+ #
101
+ # * Indentation is enabled by providing the number of spaces to
102
+ # indent for each level as a second argument to XmlBuilder.new.
103
+ # Initial indentation may be specified using a third parameter.
104
+ #
105
+ # Example:
106
+ #
107
+ # xm = Builder.new(:indent=>2)
108
+ # # xm will produce nicely formatted and indented XML.
109
+ #
110
+ # xm = Builder.new(:indent=>2, :margin=>4)
111
+ # # xm will produce nicely formatted and indented XML with 2
112
+ # # spaces per indent and an over all indentation level of 4.
113
+ #
114
+ # builder = JsonBuilder::JsonMarkup.new(:target=>$stdout, :indent=>2)
115
+ # builder.name { |b| b.first("Jim"); b.last("Weirich) }
116
+ # # prints:
117
+ # # <name>
118
+ # # <first>Jim</first>
119
+ # # <last>Weirich</last>
120
+ # # </name>
121
+ #
122
+ # * The instance_eval implementation which forces self to refer to
123
+ # the message receiver as self is now obsolete. We now use normal
124
+ # block calls to execute the markup block. This means that all
125
+ # markup methods must now be explicitly send to the xml builder.
126
+ # For instance, instead of
127
+ #
128
+ # xml.div { strong("text") }
129
+ #
130
+ # you need to write:
131
+ #
132
+ # xml.div { xml.strong("text") }
133
+ #
134
+ # Although more verbose, the subtle change in semantics within the
135
+ # block was found to be prone to error. To make this change a
136
+ # little less cumbersome, the markup block now gets the markup
137
+ # object sent as an argument, allowing you to use a shorter alias
138
+ # within the block.
139
+ #
140
+ # For example:
141
+ #
142
+ # xml_builder = JsonBuilder::JsonMarkup.new
143
+ # xml_builder.div { |xml|
144
+ # xml.stong("text")
145
+ # }
146
+ #
147
+ class JsonMarkup < JsonBase
148
+
149
+ # Create an XML markup builder. Parameters are specified by an
150
+ # option hash.
151
+ #
152
+ # :target=><em>target_object</em>::
153
+ # Object receiving the markup. +target_object+ must respond to
154
+ # the <tt><<(<em>a_string</em>)</tt> operator and return
155
+ # itself. The default target is a plain string target.
156
+ #
157
+ # :indent=><em>indentation</em>::
158
+ # Number of spaces used for indentation. The default is no
159
+ # indentation and no line breaks.
160
+ #
161
+ # :margin=><em>initial_indentation_level</em>::
162
+ # Amount of initial indentation (specified in levels, not
163
+ # spaces).
164
+ #
165
+ # :escape_attrs=><em>OBSOLETE</em>::
166
+ # The :escape_attrs option is no longer supported by builder
167
+ # (and will be quietly ignored). String attribute values are
168
+ # now automatically escaped. If you need unescaped attribute
169
+ # values (perhaps you are using entities in the attribute
170
+ # values), then give the value as a Symbol. This allows much
171
+ # finer control over escaping attribute values.
172
+ #
173
+ def initialize(options={})
174
+ super()
175
+ @target = options[:target] || ''
176
+ end
177
+
178
+ # Return the target of the builder.
179
+ def target!
180
+ @target
181
+ end
182
+
183
+ private
184
+
185
+ # NOTE: All private methods of a builder object are prefixed when
186
+ # a "_" character to avoid possible conflict with XML tag names.
187
+
188
+ # Insert text directly in to the builder's target.
189
+ def _text(text)
190
+ @target << "#{text},"
191
+ end
192
+
193
+ # Start an JSON object. If <tt>end_too</tt> is true, then the start
194
+ # tag is also the end tag (e.g. <br/>
195
+ def _start_tag(sym)
196
+ case @target.last
197
+ when ['}',','] then @target << '{'
198
+ end
199
+
200
+ @target << "\"#{sym}\":{"
201
+ end
202
+
203
+ # Start an XML tag. If <tt>end_too</tt> is true, then the start
204
+ # tag is also the end tag (e.g. <br/>
205
+ def _start_attr(sym)
206
+ @target << "\"#{sym}\":"
207
+ end
208
+
209
+ # Insert an ending tag.
210
+ def _end_tag
211
+ @target << '}'
212
+ end
213
+
214
+ def _ensure_no_block(got_block)
215
+ if got_block
216
+ fail IllegalBlockError,
217
+ "Blocks are not allowed on JSON instructions"
218
+ end
219
+ end
220
+
221
+ end
222
+
223
+ end
224
+
225
+ class String
226
+ def last
227
+ self.split('')[self.length-1]
228
+ end
229
+ end
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # The XChar library is provided courtesy of Sam Ruby (See
4
+ # http://intertwingly.net/stories/2005/09/28/xchar.rb)
5
+
6
+ # --------------------------------------------------------------------
7
+
8
+ # If the JsonBuilder::XChar module is not currently defined, fail on any
9
+ # name clashes in standard library classes.
10
+
11
+ module JsonBuilder
12
+ def self.check_for_name_collision(klass, method_name, defined_constant=nil)
13
+ if klass.instance_methods.include?(method_name.to_s)
14
+ fail RuntimeError,
15
+ "Name Collision: Method '#{method_name}' is already defined in #{klass}"
16
+ end
17
+ end
18
+ end
19
+
20
+ if ! defined?(JsonBuilder::XChar)
21
+ JsonBuilder.check_for_name_collision(String, "to_xs")
22
+ JsonBuilder.check_for_name_collision(Fixnum, "xchr")
23
+ end
24
+
25
+ ######################################################################
26
+ module JsonBuilder
27
+
28
+ ####################################################################
29
+ # XML Character converter, from Sam Ruby:
30
+ # (see http://intertwingly.net/stories/2005/09/28/xchar.rb).
31
+ #
32
+ module XChar # :nodoc:
33
+
34
+ # See
35
+ # http://intertwingly.net/stories/2004/04/14/i18n.html#CleaningWindows
36
+ # for details.
37
+ CP1252 = { # :nodoc:
38
+ 128 => 8364, # euro sign
39
+ 130 => 8218, # single low-9 quotation mark
40
+ 131 => 402, # latin small letter f with hook
41
+ 132 => 8222, # double low-9 quotation mark
42
+ 133 => 8230, # horizontal ellipsis
43
+ 134 => 8224, # dagger
44
+ 135 => 8225, # double dagger
45
+ 136 => 710, # modifier letter circumflex accent
46
+ 137 => 8240, # per mille sign
47
+ 138 => 352, # latin capital letter s with caron
48
+ 139 => 8249, # single left-pointing angle quotation mark
49
+ 140 => 338, # latin capital ligature oe
50
+ 142 => 381, # latin capital letter z with caron
51
+ 145 => 8216, # left single quotation mark
52
+ 146 => 8217, # right single quotation mark
53
+ 147 => 8220, # left double quotation mark
54
+ 148 => 8221, # right double quotation mark
55
+ 149 => 8226, # bullet
56
+ 150 => 8211, # en dash
57
+ 151 => 8212, # em dash
58
+ 152 => 732, # small tilde
59
+ 153 => 8482, # trade mark sign
60
+ 154 => 353, # latin small letter s with caron
61
+ 155 => 8250, # single right-pointing angle quotation mark
62
+ 156 => 339, # latin small ligature oe
63
+ 158 => 382, # latin small letter z with caron
64
+ 159 => 376, # latin capital letter y with diaeresis
65
+ }
66
+
67
+ # See http://www.w3.org/TR/REC-xml/#dt-chardata for details.
68
+ PREDEFINED = {
69
+ 38 => '&amp;', # ampersand
70
+ 60 => '&lt;', # left angle bracket
71
+ 62 => '&gt;', # right angle bracket
72
+ }
73
+
74
+ # See http://www.w3.org/TR/REC-xml/#charsets for details.
75
+ VALID = [
76
+ 0x9, 0xA, 0xD,
77
+ (0x20..0xD7FF),
78
+ (0xE000..0xFFFD),
79
+ (0x10000..0x10FFFF)
80
+ ]
81
+ end
82
+
83
+ end
84
+
85
+
86
+ ######################################################################
87
+ # Enhance the Fixnum class with a XML escaped character conversion.
88
+ #
89
+ class Fixnum
90
+ XChar = JsonBuilder::XChar if ! defined?(XChar)
91
+
92
+ # XML escaped version of chr. When <tt>escape</tt> is set to false
93
+ # the CP1252 fix is still applied but utf-8 characters are not
94
+ # converted to character entities.
95
+ def xchr(escape=true)
96
+ n = XChar::CP1252[self] || self
97
+ case n when *XChar::VALID
98
+ XChar::PREDEFINED[n] or (n<128 ? n.chr : (escape ? "&##{n};" : [n].pack('U*')))
99
+ else
100
+ '*'
101
+ end
102
+ end
103
+ end
104
+
105
+
106
+ ######################################################################
107
+ # Enhance the String class with a XML escaped character version of
108
+ # to_s.
109
+ #
110
+ class String
111
+ # XML escaped version of to_s. When <tt>escape</tt> is set to false
112
+ # the CP1252 fix is still applied but utf-8 characters are not
113
+ # converted to character entities.
114
+ def to_xs(escape=true)
115
+ unpack('U*').map {|n| n.xchr(escape)}.join # ASCII, UTF-8
116
+ rescue
117
+ unpack('C*').map {|n| n.xchr}.join # ISO-8859-1, WIN-1252
118
+ end
119
+ end
data/lib/test.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'json_builder'
2
+ @json = JsonBuilder::JsonMarkup.new
3
+ string = @json.user do
4
+ @json.name "Garrett"
5
+ @json.email "xhtmlthis@me.com"
6
+ @json.avatar do
7
+ @json.url "http://url.com"
8
+ @json.sizes do
9
+ @json.bool true
10
+ @json.sizes 123123123123
11
+ @json.floats 13.37
12
+ @json.small "small"
13
+ @json.tiny "tiny"
14
+ @json.large "large"
15
+ end
16
+ end
17
+ end
18
+
19
+ user = JSON.parse(string)
20
+ puts user['user']['name']
21
+ # puts string
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: json_builder
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 1
9
+ version: 1.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Garrett Bjerkhoel
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-06-25 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: json
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 4
30
+ - 3
31
+ version: 1.4.3
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ description: JSON Builder
35
+ email: garrett@clientend.com
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files: []
41
+
42
+ files:
43
+ - lib/blankslate.rb
44
+ - lib/json_builder/blankslate.rb
45
+ - lib/json_builder/jsonbase.rb
46
+ - lib/json_builder/jsonevents.rb
47
+ - lib/json_builder/jsonmarkup.rb
48
+ - lib/json_builder/xchar.rb
49
+ - lib/json_builder.rb
50
+ - lib/test.rb
51
+ has_rdoc: true
52
+ homepage: http://www.clientend.com
53
+ licenses: []
54
+
55
+ post_install_message:
56
+ rdoc_options: []
57
+
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ segments:
65
+ - 1
66
+ - 8
67
+ - 7
68
+ version: 1.8.7
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ requirements:
77
+ - none
78
+ rubyforge_project:
79
+ rubygems_version: 1.3.6
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: A JSON Builder for Rails
83
+ test_files: []
84
+