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 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!