json_builder 1.1.2 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.md +86 -0
- data/lib/blankslate.rb +3 -3
- data/lib/json_builder.rb +5 -6
- data/lib/json_builder/generator.rb +105 -0
- data/lib/json_builder/template.rb +27 -0
- data/lib/json_builder/version.rb +3 -0
- data/test/benchmarks/speed.rb +85 -0
- data/test/fixtures/simple.rb +28 -0
- data/test/test_helper.rb +4 -0
- metadata +71 -31
- data/lib/json_builder/blankslate.rb +0 -22
- data/lib/json_builder/jsonbase.rb +0 -131
- data/lib/json_builder/jsonevents.rb +0 -52
- data/lib/json_builder/jsonmarkup.rb +0 -229
- data/lib/json_builder/xchar.rb +0 -105
- data/lib/test.rb +0 -35
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Garrett Bjerkhoel
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
# JSON Builder
|
2
|
+
Rails provides an excellent XML Builder by default to build RSS and ATOM feeds, but nothing to help you build complex and custom JSON data structures. The standard `to_json` works well, but can get very verbose when you need full control of what is generated. JSON Builder hopes to solve that problem.
|
3
|
+
|
4
|
+
## Using JSON Builder with Rails
|
5
|
+
First, make sure to add the gem to your `Gemfile`.
|
6
|
+
|
7
|
+
gem 'json_builder'
|
8
|
+
|
9
|
+
Not required, but if you'd like to run the generated JSON through a prettifier for debugging reasons, just set `config.action_view.pretty_print_json` to `true` in your environment config. It defaults to false for speed.
|
10
|
+
|
11
|
+
Your::Application.configure do
|
12
|
+
config.action_view.pretty_print_json = true
|
13
|
+
end
|
14
|
+
|
15
|
+
Second, make sure your controller responds to `json`:
|
16
|
+
|
17
|
+
class PostsController < ApplicationController
|
18
|
+
respond_to :json
|
19
|
+
|
20
|
+
def index
|
21
|
+
@posts = Post.all
|
22
|
+
respond_with @posts
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
Lastly, create `app/views/posts/index.json.builder` which could look something like:
|
27
|
+
|
28
|
+
json.posts do
|
29
|
+
json.array! @posts do
|
30
|
+
@posts.each do |user|
|
31
|
+
json.array_item! do
|
32
|
+
render :partial => 'post', :locals => { :json => json, :post => post }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
You will get something like:
|
39
|
+
|
40
|
+
{
|
41
|
+
"posts": [
|
42
|
+
{
|
43
|
+
"id": 1,
|
44
|
+
"name": "Garrett Bjerkhoel",
|
45
|
+
"body": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
|
46
|
+
}, {
|
47
|
+
"id": 2,
|
48
|
+
"name": "John Doe",
|
49
|
+
"body": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
|
50
|
+
}
|
51
|
+
]
|
52
|
+
}
|
53
|
+
|
54
|
+
## Sample Usage
|
55
|
+
|
56
|
+
require 'json_builder'
|
57
|
+
json = JSONBuilder::Generator.new
|
58
|
+
|
59
|
+
json.name "Garrett Bjerkhoel"
|
60
|
+
json.address do
|
61
|
+
json.street "1143 1st Ave"
|
62
|
+
json.street2 "Apt 1"
|
63
|
+
json.city "New York"
|
64
|
+
json.state "NY"
|
65
|
+
json.zip 10065
|
66
|
+
end
|
67
|
+
json.skills do
|
68
|
+
json.ruby true
|
69
|
+
json.asp false
|
70
|
+
end
|
71
|
+
|
72
|
+
puts json.compile!
|
73
|
+
|
74
|
+
## Speed
|
75
|
+
JSON Builder is very fast, it's roughly 6 times faster than the core XML Builder based on the [speed benchmark](http://github.com/dewski/json_builder/blob/master/test/benchmarks/speed.rb).
|
76
|
+
|
77
|
+
user system total real
|
78
|
+
JSON Builder 0.700000 0.030000 0.730000 (0.724748)
|
79
|
+
JSON Builder Pretty 1.080000 0.060000 1.140000 (1.149416)
|
80
|
+
XML Builder 4.700000 0.110000 4.810000 (4.822932)
|
81
|
+
|
82
|
+
## Examples
|
83
|
+
See the [examples](http://github.com/dewski/json_builder/tree/master/examples) directory.
|
84
|
+
|
85
|
+
## Copyright
|
86
|
+
Copyright © 2010 Garrett Bjerkhoel. See [MIT-LICENSE](http://github.com/dewski/json_builder/blob/master/MIT-LICENSE) for details.
|
data/lib/blankslate.rb
CHANGED
@@ -16,7 +16,7 @@
|
|
16
16
|
#
|
17
17
|
class BlankSlate
|
18
18
|
class << self
|
19
|
-
|
19
|
+
|
20
20
|
# Hide the method named +name+ in the BlankSlate class. Don't
|
21
21
|
# hide +instance_eval+ or any method beginning with "__".
|
22
22
|
def hide(name)
|
@@ -41,7 +41,7 @@ class BlankSlate
|
|
41
41
|
define_method(name, hidden_method)
|
42
42
|
end
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
45
|
instance_methods.each { |m| hide(m) }
|
46
46
|
end
|
47
47
|
|
@@ -106,4 +106,4 @@ class Module
|
|
106
106
|
end
|
107
107
|
result
|
108
108
|
end
|
109
|
-
end
|
109
|
+
end
|
data/lib/json_builder.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
require 'json_builder/
|
2
|
-
require 'json_builder/
|
1
|
+
require 'json_builder/version'
|
2
|
+
require 'json_builder/generator'
|
3
3
|
|
4
|
-
|
5
|
-
require '
|
6
|
-
|
7
|
-
end
|
4
|
+
if defined? Rails
|
5
|
+
require 'json_builder/template'
|
6
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'blankslate' unless defined?(BlankSlate)
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module JSONBuilder
|
6
|
+
class Generator < BlankSlate
|
7
|
+
def initialize(options=nil)
|
8
|
+
@pretty_print ||= options.delete(:pretty) if !options.nil? && options[:pretty] # don't want nil
|
9
|
+
@compiled = []
|
10
|
+
@indent = 0
|
11
|
+
@passed_items = 0
|
12
|
+
@indent_next = false
|
13
|
+
@is_array = false
|
14
|
+
end
|
15
|
+
|
16
|
+
def inspect
|
17
|
+
compile!
|
18
|
+
end
|
19
|
+
|
20
|
+
def tag!(sym, *args, &block)
|
21
|
+
method_missing(sym.to_sym, *args, &block)
|
22
|
+
end
|
23
|
+
|
24
|
+
def array!(set, &block)
|
25
|
+
@array_length = set.length if set.is_a?(Array)
|
26
|
+
@is_array = true
|
27
|
+
method_missing(nil, nil, &block)
|
28
|
+
end
|
29
|
+
|
30
|
+
def array_item!(&block)
|
31
|
+
method_missing(nil, nil, &block)
|
32
|
+
|
33
|
+
@passed_items += 1
|
34
|
+
@compiled << '},{' if @passed_items < @array_length
|
35
|
+
end
|
36
|
+
|
37
|
+
def method_missing(sym, *args, &block)
|
38
|
+
text = type_cast(args.first)
|
39
|
+
|
40
|
+
if block
|
41
|
+
start_block(sym) unless sym.nil?
|
42
|
+
block.call(self)
|
43
|
+
end_block unless sym.nil?
|
44
|
+
else
|
45
|
+
if @indent_next
|
46
|
+
@compiled[@compiled.length-1] = @compiled.last + "\"#{sym}\":#{text}"
|
47
|
+
@indent_next = false
|
48
|
+
else
|
49
|
+
@compiled << "\"#{sym}\":#{text}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def compile!
|
55
|
+
if @is_array
|
56
|
+
compiled = ('[{' + @compiled.join(',') + '}]').gsub(',},{,', '},{')
|
57
|
+
else
|
58
|
+
compiled = '{' + @compiled.join(', ') + '}'
|
59
|
+
end
|
60
|
+
|
61
|
+
if @pretty_print
|
62
|
+
JSON.pretty_generate(JSON[compiled])
|
63
|
+
else
|
64
|
+
compiled
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Since most methods here are public facing,
|
69
|
+
private
|
70
|
+
def type_cast(text)
|
71
|
+
case text
|
72
|
+
when Array then '['+ text.map! { |j| type_cast(j) }.join(', ') +']'
|
73
|
+
when Hash then 'teheh'
|
74
|
+
when String then "\"#{text}\""
|
75
|
+
when TrueClass then 'true'
|
76
|
+
when FalseClass then 'false'
|
77
|
+
when NilClass then 'null'
|
78
|
+
when DateTime, Time, Date then "\"#{text.strftime("%Y-%m-%dT%H:%M:%S")}\""
|
79
|
+
when Fixnum then text
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def start_indent
|
84
|
+
@indent += 1
|
85
|
+
end
|
86
|
+
|
87
|
+
def end_indent
|
88
|
+
@indent -= 1
|
89
|
+
end
|
90
|
+
|
91
|
+
def start_block(sym)
|
92
|
+
start_indent
|
93
|
+
@indent_next = true
|
94
|
+
@compiled << "\"#{sym}\":{"
|
95
|
+
end
|
96
|
+
|
97
|
+
def end_block
|
98
|
+
if @indent > 0
|
99
|
+
@compiled[@compiled.length-1] = @compiled.last + '}'
|
100
|
+
else
|
101
|
+
@compiled << '}'
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'action_view/base'
|
2
|
+
require 'action_view/template'
|
3
|
+
|
4
|
+
module ActionView #:nodoc:
|
5
|
+
class Base
|
6
|
+
cattr_accessor :pretty_print_json
|
7
|
+
@@pretty_print_json = false
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module ActionView
|
12
|
+
module Template::Handlers
|
13
|
+
class JSONBuilder < Template::Handler
|
14
|
+
include Compilable
|
15
|
+
|
16
|
+
self.default_format = Mime::JSON
|
17
|
+
|
18
|
+
def compile(template)
|
19
|
+
"json = ::JSONBuilder::Generator.new(:pretty => #{ActionView::Base.pretty_print_json});" +
|
20
|
+
template.source +
|
21
|
+
";json.compile!;"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
ActionView::Template.register_template_handler :'json.builder', ActionView::Template::Handlers::JSONBuilder
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'benchmark'
|
3
|
+
require 'builder'
|
4
|
+
require 'json_builder'
|
5
|
+
|
6
|
+
Benchmark.bm do |b|
|
7
|
+
b.report('JSON') do
|
8
|
+
15000.times {
|
9
|
+
j = JSONBuilder::Generator.new
|
10
|
+
j.name "Garrett Bjerkhoel"
|
11
|
+
j.birthday Time.local(1991, 9, 14)
|
12
|
+
j.street do
|
13
|
+
j.address "1143 1st Ave"
|
14
|
+
j.address2 "Apt 200"
|
15
|
+
j.city "New York"
|
16
|
+
j.state "New York"
|
17
|
+
j.zip 10065
|
18
|
+
end
|
19
|
+
j.skills do
|
20
|
+
j.ruby true
|
21
|
+
j.asp false
|
22
|
+
j.php true
|
23
|
+
j.mysql true
|
24
|
+
j.mongodb true
|
25
|
+
j.haproxy true
|
26
|
+
j.marathon false
|
27
|
+
end
|
28
|
+
j.single_skills ['ruby', 'php', 'mysql', 'mongodb', 'haproxy']
|
29
|
+
j.booleans [true, true, false, nil]
|
30
|
+
j.compile!
|
31
|
+
}
|
32
|
+
end
|
33
|
+
b.report('JSON Pretty') do
|
34
|
+
15000.times {
|
35
|
+
j = JSONBuilder::Generator.new(:pretty => true)
|
36
|
+
j.name "Garrett Bjerkhoel"
|
37
|
+
j.birthday Time.local(1991, 9, 14)
|
38
|
+
j.street do
|
39
|
+
j.address "1143 1st Ave"
|
40
|
+
j.address2 "Apt 200"
|
41
|
+
j.city "New York"
|
42
|
+
j.state "New York"
|
43
|
+
j.zip 10065
|
44
|
+
end
|
45
|
+
j.skills do
|
46
|
+
j.ruby true
|
47
|
+
j.asp false
|
48
|
+
j.php true
|
49
|
+
j.mysql true
|
50
|
+
j.mongodb true
|
51
|
+
j.haproxy true
|
52
|
+
j.marathon false
|
53
|
+
end
|
54
|
+
j.single_skills ['ruby', 'php', 'mysql', 'mongodb', 'haproxy']
|
55
|
+
j.booleans [true, true, false, nil]
|
56
|
+
j.compile!
|
57
|
+
}
|
58
|
+
end
|
59
|
+
b.report('Builder') do
|
60
|
+
15000.times {
|
61
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
62
|
+
xml.name "Garrett Bjerkhoel"
|
63
|
+
xml.birthday Time.local(1991, 9, 14)
|
64
|
+
xml.street do
|
65
|
+
xml.address "1143 1st Ave"
|
66
|
+
xml.address2 "Apt 200"
|
67
|
+
xml.city "New York"
|
68
|
+
xml.state "New York"
|
69
|
+
xml.zip 10065
|
70
|
+
end
|
71
|
+
xml.skills do
|
72
|
+
xml.ruby true
|
73
|
+
xml.asp false
|
74
|
+
xml.php true
|
75
|
+
xml.mysql true
|
76
|
+
xml.mongodb true
|
77
|
+
xml.haproxy true
|
78
|
+
xml.marathon false
|
79
|
+
end
|
80
|
+
xml.single_skills ['ruby', 'php', 'mysql', 'mongodb', 'haproxy']
|
81
|
+
xml.booleans [true, true, false, nil]
|
82
|
+
xml.target!
|
83
|
+
}
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'json_builder'
|
2
|
+
j = JSONBuilder::Generator.new
|
3
|
+
|
4
|
+
j.name "Garrett Bjerkhoel"
|
5
|
+
j.birthday Time.local(1991, 9, 14)
|
6
|
+
j.street do
|
7
|
+
j.address "1143 1st Ave"
|
8
|
+
j.address2 "Apt 200"
|
9
|
+
j.city "New York"
|
10
|
+
j.state "New York"
|
11
|
+
j.zip 10065
|
12
|
+
end
|
13
|
+
j.hashed {
|
14
|
+
:my_name => "Garrett Bjerkhoel".split('')
|
15
|
+
}
|
16
|
+
j.skills do
|
17
|
+
j.ruby true
|
18
|
+
j.asp false
|
19
|
+
j.php true
|
20
|
+
j.mysql true
|
21
|
+
j.mongodb true
|
22
|
+
j.haproxy true
|
23
|
+
j.marathon false
|
24
|
+
end
|
25
|
+
j.single_skills ['ruby', 'php', 'mysql', 'mongodb', 'haproxy']
|
26
|
+
j.booleans [true, true, false, nil]
|
27
|
+
|
28
|
+
puts j.compile!
|
data/test/test_helper.rb
ADDED
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json_builder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 15
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
|
-
- 1
|
7
|
-
- 1
|
8
7
|
- 2
|
9
|
-
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 2.0.0
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Garrett Bjerkhoel
|
@@ -14,71 +15,110 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2010-
|
18
|
+
date: 2010-08-27 00:00:00 -07:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
|
-
name:
|
22
|
+
name: activesupport
|
22
23
|
prerelease: false
|
23
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
24
26
|
requirements:
|
25
27
|
- - ~>
|
26
28
|
- !ruby/object:Gem::Version
|
29
|
+
hash: 7
|
27
30
|
segments:
|
28
|
-
- 1
|
29
|
-
- 4
|
30
31
|
- 3
|
31
|
-
|
32
|
+
- 0
|
33
|
+
- 0
|
34
|
+
version: 3.0.0
|
32
35
|
type: :runtime
|
33
36
|
version_requirements: *id001
|
34
|
-
|
35
|
-
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: actionpack
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 7
|
46
|
+
segments:
|
47
|
+
- 3
|
48
|
+
- 0
|
49
|
+
- 0
|
50
|
+
version: 3.0.0
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: json
|
55
|
+
prerelease: false
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 3
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
type: :runtime
|
66
|
+
version_requirements: *id003
|
67
|
+
description: JSON Builder for Rails
|
68
|
+
email: me@garrettbjerkhoel.com
|
36
69
|
executables: []
|
37
70
|
|
38
71
|
extensions: []
|
39
72
|
|
40
|
-
extra_rdoc_files:
|
41
|
-
|
73
|
+
extra_rdoc_files:
|
74
|
+
- MIT-LICENSE
|
75
|
+
- README.md
|
42
76
|
files:
|
77
|
+
- MIT-LICENSE
|
78
|
+
- README.md
|
43
79
|
- 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
80
|
- lib/json_builder.rb
|
50
|
-
- lib/
|
81
|
+
- lib/json_builder/generator.rb
|
82
|
+
- lib/json_builder/template.rb
|
83
|
+
- lib/json_builder/version.rb
|
84
|
+
- test/benchmarks/speed.rb
|
85
|
+
- test/fixtures/simple.rb
|
86
|
+
- test/test_helper.rb
|
51
87
|
has_rdoc: true
|
52
|
-
homepage: http://
|
88
|
+
homepage: http://github.com/dewski/json_builder
|
53
89
|
licenses: []
|
54
90
|
|
55
91
|
post_install_message:
|
56
|
-
rdoc_options:
|
57
|
-
|
92
|
+
rdoc_options:
|
93
|
+
- --charset=UTF-8
|
58
94
|
require_paths:
|
59
95
|
- lib
|
60
96
|
required_ruby_version: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
61
98
|
requirements:
|
62
99
|
- - ">="
|
63
100
|
- !ruby/object:Gem::Version
|
101
|
+
hash: 3
|
64
102
|
segments:
|
65
|
-
-
|
66
|
-
|
67
|
-
- 7
|
68
|
-
version: 1.8.7
|
103
|
+
- 0
|
104
|
+
version: "0"
|
69
105
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
70
107
|
requirements:
|
71
108
|
- - ">="
|
72
109
|
- !ruby/object:Gem::Version
|
110
|
+
hash: 3
|
73
111
|
segments:
|
74
112
|
- 0
|
75
113
|
version: "0"
|
76
|
-
requirements:
|
77
|
-
|
114
|
+
requirements: []
|
115
|
+
|
78
116
|
rubyforge_project:
|
79
|
-
rubygems_version: 1.3.
|
117
|
+
rubygems_version: 1.3.7
|
80
118
|
signing_key:
|
81
119
|
specification_version: 3
|
82
|
-
summary:
|
83
|
-
test_files:
|
84
|
-
|
120
|
+
summary: JSON Builder
|
121
|
+
test_files:
|
122
|
+
- test/benchmarks/speed.rb
|
123
|
+
- test/fixtures/simple.rb
|
124
|
+
- test/test_helper.rb
|
@@ -1,22 +0,0 @@
|
|
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
|
@@ -1,131 +0,0 @@
|
|
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
|
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{"}, '"') # " WART
|
125
|
-
end
|
126
|
-
|
127
|
-
def _newline
|
128
|
-
text! "\n"
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
@@ -1,52 +0,0 @@
|
|
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
|
@@ -1,229 +0,0 @@
|
|
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 & 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 <,
|
50
|
-
# > and & 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.gsub!(/,(\}|\}+)$/, '\1')
|
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
|
data/lib/json_builder/xchar.rb
DELETED
@@ -1,105 +0,0 @@
|
|
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
|
-
######################################################################
|
12
|
-
module JsonBuilder
|
13
|
-
|
14
|
-
####################################################################
|
15
|
-
# XML Character converter, from Sam Ruby:
|
16
|
-
# (see http://intertwingly.net/stories/2005/09/28/xchar.rb).
|
17
|
-
#
|
18
|
-
module XChar # :nodoc:
|
19
|
-
|
20
|
-
# See
|
21
|
-
# http://intertwingly.net/stories/2004/04/14/i18n.html#CleaningWindows
|
22
|
-
# for details.
|
23
|
-
CP1252 = { # :nodoc:
|
24
|
-
128 => 8364, # euro sign
|
25
|
-
130 => 8218, # single low-9 quotation mark
|
26
|
-
131 => 402, # latin small letter f with hook
|
27
|
-
132 => 8222, # double low-9 quotation mark
|
28
|
-
133 => 8230, # horizontal ellipsis
|
29
|
-
134 => 8224, # dagger
|
30
|
-
135 => 8225, # double dagger
|
31
|
-
136 => 710, # modifier letter circumflex accent
|
32
|
-
137 => 8240, # per mille sign
|
33
|
-
138 => 352, # latin capital letter s with caron
|
34
|
-
139 => 8249, # single left-pointing angle quotation mark
|
35
|
-
140 => 338, # latin capital ligature oe
|
36
|
-
142 => 381, # latin capital letter z with caron
|
37
|
-
145 => 8216, # left single quotation mark
|
38
|
-
146 => 8217, # right single quotation mark
|
39
|
-
147 => 8220, # left double quotation mark
|
40
|
-
148 => 8221, # right double quotation mark
|
41
|
-
149 => 8226, # bullet
|
42
|
-
150 => 8211, # en dash
|
43
|
-
151 => 8212, # em dash
|
44
|
-
152 => 732, # small tilde
|
45
|
-
153 => 8482, # trade mark sign
|
46
|
-
154 => 353, # latin small letter s with caron
|
47
|
-
155 => 8250, # single right-pointing angle quotation mark
|
48
|
-
156 => 339, # latin small ligature oe
|
49
|
-
158 => 382, # latin small letter z with caron
|
50
|
-
159 => 376, # latin capital letter y with diaeresis
|
51
|
-
}
|
52
|
-
|
53
|
-
# See http://www.w3.org/TR/REC-xml/#dt-chardata for details.
|
54
|
-
PREDEFINED = {
|
55
|
-
38 => '&', # ampersand
|
56
|
-
60 => '<', # left angle bracket
|
57
|
-
62 => '>', # right angle bracket
|
58
|
-
}
|
59
|
-
|
60
|
-
# See http://www.w3.org/TR/REC-xml/#charsets for details.
|
61
|
-
VALID = [
|
62
|
-
0x9, 0xA, 0xD,
|
63
|
-
(0x20..0xD7FF),
|
64
|
-
(0xE000..0xFFFD),
|
65
|
-
(0x10000..0x10FFFF)
|
66
|
-
]
|
67
|
-
end
|
68
|
-
|
69
|
-
end
|
70
|
-
|
71
|
-
|
72
|
-
######################################################################
|
73
|
-
# Enhance the Fixnum class with a XML escaped character conversion.
|
74
|
-
#
|
75
|
-
class Fixnum
|
76
|
-
XChar = JsonBuilder::XChar if !defined?(XChar)
|
77
|
-
|
78
|
-
# XML escaped version of chr. When <tt>escape</tt> is set to false
|
79
|
-
# the CP1252 fix is still applied but utf-8 characters are not
|
80
|
-
# converted to character entities.
|
81
|
-
def xchr(escape=true)
|
82
|
-
n = XChar::CP1252[self] || self
|
83
|
-
case n when *XChar::VALID
|
84
|
-
XChar::PREDEFINED[n] or (n<128 ? n.chr : (escape ? "&##{n};" : [n].pack('U*')))
|
85
|
-
else
|
86
|
-
'*'
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
|
92
|
-
######################################################################
|
93
|
-
# Enhance the String class with a XML escaped character version of
|
94
|
-
# to_s.
|
95
|
-
#
|
96
|
-
class String
|
97
|
-
# XML escaped version of to_s. When <tt>escape</tt> is set to false
|
98
|
-
# the CP1252 fix is still applied but utf-8 characters are not
|
99
|
-
# converted to character entities.
|
100
|
-
def to_xs(escape=true)
|
101
|
-
unpack('U*').map {|n| n.xchr(escape)}.join # ASCII, UTF-8
|
102
|
-
rescue
|
103
|
-
unpack('C*').map {|n| n.xchr}.join # ISO-8859-1, WIN-1252
|
104
|
-
end
|
105
|
-
end
|
data/lib/test.rb
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'json_builder'
|
3
|
-
@json = JsonBuilder::JsonMarkup.new
|
4
|
-
string = @json.user do
|
5
|
-
@json.name "Garrett"
|
6
|
-
@json.email "xhtmlthis@me.com"
|
7
|
-
@json.avatar do
|
8
|
-
@json.url "http://url.com"
|
9
|
-
@json.sizes do
|
10
|
-
@json.bool true
|
11
|
-
@json.sizes 123123123123
|
12
|
-
@json.floats 13.37
|
13
|
-
@json.small "small"
|
14
|
-
@json.tiny "tiny"
|
15
|
-
@json.large "large"
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
puts string
|
21
|
-
|
22
|
-
@json2 = JsonBuilder::JsonMarkup.new
|
23
|
-
@json2.id 1
|
24
|
-
@json2.name "Client End"
|
25
|
-
@json2.slug "client-end"
|
26
|
-
@json2.subdomain "clientend"
|
27
|
-
@json2.hosted_domain "127.0.0.1"
|
28
|
-
@json2.clients_count 15
|
29
|
-
@json2.total_file_size 13123123
|
30
|
-
@json2.last_billed_on Time.now.getutc.iso8601
|
31
|
-
@json2.logo_url "http://google.com/logo.gif"
|
32
|
-
@json2.created_at Time.now.getutc.iso8601
|
33
|
-
@json2.updated_at Time.now.getutc.iso8601
|
34
|
-
|
35
|
-
puts @json2.target!
|