json_builder 1.1.2 → 2.0.0

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/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/jsonmarkup'
2
- require 'json_builder/jsonevents'
1
+ require 'json_builder/version'
2
+ require 'json_builder/generator'
3
3
 
4
- unless defined?(Rails)
5
- require 'rubygems'
6
- require 'json'
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,3 @@
1
+ module JSONBuilder
2
+ VERSION = '2.0.0'
3
+ end
@@ -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!
@@ -0,0 +1,4 @@
1
+ ROOT = File.join(File.dirname(__FILE__), '..')
2
+ $:.unshift File.join(ROOT, 'lib')
3
+ $:.unshift File.join(ROOT, 'lib', 'json_builder')
4
+ require 'json_builder'
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
- version: 1.1.2
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-06-25 00:00:00 -04:00
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: json
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
- version: 1.4.3
32
+ - 0
33
+ - 0
34
+ version: 3.0.0
32
35
  type: :runtime
33
36
  version_requirements: *id001
34
- description: JSON Builder
35
- email: garrett@clientend.com
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/test.rb
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://www.clientend.com
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
- - 1
66
- - 8
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
- - none
114
+ requirements: []
115
+
78
116
  rubyforge_project:
79
- rubygems_version: 1.3.6
117
+ rubygems_version: 1.3.7
80
118
  signing_key:
81
119
  specification_version: 3
82
- summary: A JSON Builder for Rails
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{"}, '&quot;') # " 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 &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.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
@@ -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 => '&amp;', # ampersand
56
- 60 => '&lt;', # left angle bracket
57
- 62 => '&gt;', # 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!