json_builder 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+