ox-builder 0.1.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/.travis.yml +7 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +0 -2
- data/README.md +197 -8
- data/benchmarks/data/countries.yml +2503 -0
- data/benchmarks/huge.rb +25 -0
- data/benchmarks/medium.rb +27 -0
- data/benchmarks/runner.rb +6 -0
- data/benchmarks/small.rb +20 -0
- data/benchmarks/templates/large.builder +20 -0
- data/benchmarks/templates/large.ox +20 -0
- data/benchmarks/templates/small.builder +7 -0
- data/benchmarks/templates/small.ox +7 -0
- data/bin/console +4 -0
- data/lib/ox/builder/action_view/template_handler.rb +21 -0
- data/lib/ox/builder/dsl.rb +42 -0
- data/lib/ox/builder/factory.rb +39 -0
- data/lib/ox/builder/fallback_context_proxy.rb +30 -0
- data/lib/ox/builder/version.rb +1 -1
- data/lib/ox/builder.rb +29 -2
- data/lib/tilt/ox_builder_template.rb +28 -0
- data/ox-builder.gemspec +9 -1
- metadata +116 -3
data/benchmarks/huge.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative './runner'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
Country = Struct.new(:code, :name, :population, :north, :south, :east, :west, :capital, :continent_name)
|
5
|
+
data = YAML.load_file('benchmarks/data/countries.yml')['countries']['country'] * 100
|
6
|
+
@countries = data.map{ |c| Country.new(*c.values) }
|
7
|
+
|
8
|
+
builder_tilt = Tilt.new('benchmarks/templates/large.builder')
|
9
|
+
ox_tilt = Tilt.new('benchmarks/templates/large.ox')
|
10
|
+
|
11
|
+
# Output is 11M
|
12
|
+
|
13
|
+
Benchmark.ips do |x|
|
14
|
+
x.config(time: 60, warmup: 10)
|
15
|
+
|
16
|
+
x.report('builder') do
|
17
|
+
builder_tilt.render(Object.new, { countries: @countries })
|
18
|
+
end
|
19
|
+
|
20
|
+
x.report('ox') do
|
21
|
+
ox_tilt.render(Object.new, { countries: @countries })
|
22
|
+
end
|
23
|
+
|
24
|
+
x.compare!
|
25
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative './runner'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
Country = Struct.new(:code, :name, :population, :north, :south, :east, :west, :capital, :continent_name)
|
5
|
+
data = YAML.load_file('benchmarks/data/countries.yml')['countries']['country']
|
6
|
+
@countries = data.map{ |c| Country.new(*c.values) }
|
7
|
+
|
8
|
+
builder_tilt = Tilt.new('benchmarks/templates/large.builder')
|
9
|
+
ox_tilt = Tilt.new('benchmarks/templates/large.ox')
|
10
|
+
|
11
|
+
File.write('ox.xml', builder_tilt.render(Object.new, { countries: @countries }))
|
12
|
+
|
13
|
+
# Output is 107K
|
14
|
+
|
15
|
+
Benchmark.ips do |x|
|
16
|
+
x.config(time: 20, warmup: 10)
|
17
|
+
|
18
|
+
x.report('builder') do
|
19
|
+
builder_tilt.render(Object.new, { countries: @countries })
|
20
|
+
end
|
21
|
+
|
22
|
+
x.report('ox') do
|
23
|
+
ox_tilt.render(Object.new, { countries: @countries })
|
24
|
+
end
|
25
|
+
|
26
|
+
x.compare!
|
27
|
+
end
|
data/benchmarks/small.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative './runner'
|
2
|
+
|
3
|
+
builder_tilt = Tilt.new('benchmarks/templates/small.builder')
|
4
|
+
ox_tilt = Tilt.new('benchmarks/templates/small.ox')
|
5
|
+
|
6
|
+
# Output is 167 bytes
|
7
|
+
|
8
|
+
Benchmark.ips do |x|
|
9
|
+
x.config(time: 10, warmup: 5)
|
10
|
+
|
11
|
+
x.report('builder') do
|
12
|
+
builder_tilt.render
|
13
|
+
end
|
14
|
+
|
15
|
+
x.report('ox') do
|
16
|
+
ox_tilt.render
|
17
|
+
end
|
18
|
+
|
19
|
+
x.compare!
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
xml.instruct!
|
2
|
+
|
3
|
+
xml.countries do
|
4
|
+
countries.each do |country|
|
5
|
+
xml.country do
|
6
|
+
xml.name { xml.cdata!(country.name) }
|
7
|
+
xml.code { xml.cdata!(country.code) }
|
8
|
+
xml.continent { xml.cdata!(country.continent_name) }
|
9
|
+
xml.capital { xml.cdata!(country.capital.to_s) }
|
10
|
+
xml.population country.population
|
11
|
+
|
12
|
+
xml.boundaries do
|
13
|
+
xml.north country.north
|
14
|
+
xml.sourth country.south
|
15
|
+
xml.east country.east
|
16
|
+
xml.west country.west
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
instruct!
|
2
|
+
|
3
|
+
countries do
|
4
|
+
countries.each do |country|
|
5
|
+
country do
|
6
|
+
name { cdata!(country.name) }
|
7
|
+
code { cdata!(country.code) }
|
8
|
+
continent { cdata!(country.continent_name) }
|
9
|
+
capital { cdata!(country.capital) }
|
10
|
+
population country.population
|
11
|
+
|
12
|
+
boundaries do
|
13
|
+
north country.north
|
14
|
+
sourth country.south
|
15
|
+
east country.east
|
16
|
+
west country.west
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/bin/console
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require "bundler/setup"
|
4
|
+
require 'active_support'
|
5
|
+
require 'active_support/hash_with_indifferent_access'
|
6
|
+
require 'action_view'
|
7
|
+
require 'tilt'
|
4
8
|
require "ox/builder"
|
5
9
|
|
6
10
|
# You can add fixtures and/or initialization code here to make experimenting
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'active_support/core_ext/class/attribute'
|
2
|
+
require 'action_dispatch/http/mime_type'
|
3
|
+
|
4
|
+
module Ox
|
5
|
+
module Builder
|
6
|
+
module ActionView
|
7
|
+
class TemplateHandler
|
8
|
+
class_attribute :default_format
|
9
|
+
self.default_format = Mime::XML
|
10
|
+
|
11
|
+
def call(template)
|
12
|
+
<<-RUBY
|
13
|
+
xml = ::Ox::Builder.build {
|
14
|
+
#{template.source}
|
15
|
+
};xml.to_xml
|
16
|
+
RUBY
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Ox
|
2
|
+
module Builder
|
3
|
+
module DSL
|
4
|
+
def instruct!(*args)
|
5
|
+
attributes = args.last.is_a?(Hash) ? args.pop : { version: '1.0', encoding: 'UTF-8' }
|
6
|
+
name = args.first || :xml
|
7
|
+
|
8
|
+
with_dsl(Ox::Instruct.new(name)) do |instruct|
|
9
|
+
instruct.add_attributes(attributes)
|
10
|
+
node << instruct.node
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def cdata!(text)
|
15
|
+
node << Ox::CData.new(text)
|
16
|
+
end
|
17
|
+
|
18
|
+
def comment!(text)
|
19
|
+
node << Ox::Comment.new(text)
|
20
|
+
end
|
21
|
+
|
22
|
+
def doctype!(type)
|
23
|
+
node << Ox::DocType.new(type)
|
24
|
+
end
|
25
|
+
|
26
|
+
def tag!(name, *args, &block)
|
27
|
+
builder = Builder.build(Ox::Element.new(name), &block).tap do |tag|
|
28
|
+
attributes = args.last.is_a?(Hash) ? args.pop : {}
|
29
|
+
|
30
|
+
tag.add_attributes(attributes)
|
31
|
+
|
32
|
+
args.each do |text|
|
33
|
+
text = text.is_a?(Ox::Node) ? text : text.to_s
|
34
|
+
tag.node << text
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
node << builder.node
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Ox
|
2
|
+
module Builder
|
3
|
+
class Factory
|
4
|
+
include DSL
|
5
|
+
|
6
|
+
attr_reader :node
|
7
|
+
|
8
|
+
def initialize(node)
|
9
|
+
@node = node
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
Ox.dump(node)
|
14
|
+
end
|
15
|
+
alias_method :to_xml, :to_s
|
16
|
+
|
17
|
+
def inspect
|
18
|
+
"#<#{self.class.name}:0x#{"%x" % object_id} node=#{node}>"
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_attributes(attributes)
|
22
|
+
attributes.each do |key, val|
|
23
|
+
node[key] = val
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
def method_missing(name, *args, &block)
|
30
|
+
name = name[0...-1] if name.to_s.end_with?('!')
|
31
|
+
tag!(name, *args, &block)
|
32
|
+
end
|
33
|
+
|
34
|
+
def with_dsl(obj, &block)
|
35
|
+
Factory.new(obj).tap(&block)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Ox
|
2
|
+
module Builder
|
3
|
+
class FallbackContextProxy < Docile::FallbackContextProxy
|
4
|
+
DSL_METHODS = DSL.instance_methods(false)
|
5
|
+
|
6
|
+
def method_missing(method, *args, &block)
|
7
|
+
# This is somewhat more complicated than the normal FallbackContextProxy provided by
|
8
|
+
# docile. The reason for this is that the Builder has its own method_missing to
|
9
|
+
# allow tags to be defined dynamically, but that can't define a respond_to_missing?
|
10
|
+
# because we don't know what the methods will be until they are accessed.
|
11
|
+
#
|
12
|
+
# Therefore, if the fallback doesn't respond to the method, send it to the receiver
|
13
|
+
# regardless of if it responds to it or not (so that its method_missing can pick it up).
|
14
|
+
#
|
15
|
+
# The next wrinkle is that we need to try the fallback before the receiver or else
|
16
|
+
# nested DSLs lose access to methods defined in the original scope. To handle this
|
17
|
+
# without allowing the core DSL methods to be clobbered, we first check if the method
|
18
|
+
# is a DSL method and if so pass it directly to the receiver.
|
19
|
+
|
20
|
+
if DSL_METHODS.include?(method.to_sym)
|
21
|
+
@__receiver__.__send__(method.to_sym, *args, &block)
|
22
|
+
elsif @__fallback__.respond_to?(method.to_sym)
|
23
|
+
@__fallback__.__send__(method.to_sym, *args, &block)
|
24
|
+
else
|
25
|
+
@__receiver__.__send__(method, *args, &block)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/ox/builder/version.rb
CHANGED
data/lib/ox/builder.rb
CHANGED
@@ -1,7 +1,34 @@
|
|
1
|
-
require
|
1
|
+
require 'ox'
|
2
|
+
require 'docile'
|
3
|
+
require 'ox/builder/version'
|
4
|
+
require 'ox/builder/dsl'
|
5
|
+
require 'ox/builder/factory'
|
6
|
+
require 'ox/builder/fallback_context_proxy'
|
2
7
|
|
3
8
|
module Ox
|
4
9
|
module Builder
|
5
|
-
|
10
|
+
class << self
|
11
|
+
def build(node = Ox::Document.new, &block)
|
12
|
+
Factory.new(node).tap do |builder|
|
13
|
+
dsl_eval(builder, builder, &block) if block_given?
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def dsl_eval(dsl, *args, &block)
|
20
|
+
Docile::Execution.exec_in_proxy_context(dsl, FallbackContextProxy, *args, &block)
|
21
|
+
end
|
22
|
+
end
|
6
23
|
end
|
7
24
|
end
|
25
|
+
|
26
|
+
if defined?(Tilt)
|
27
|
+
require 'tilt/ox_builder_template'
|
28
|
+
Tilt.register Tilt::OxBuilderTemplate, 'ox'
|
29
|
+
end
|
30
|
+
|
31
|
+
if defined?(ActionView)
|
32
|
+
require 'ox/builder/action_view/template_handler'
|
33
|
+
ActionView::Template.register_template_handler :ox, Ox::Builder::ActionView::TemplateHandler.new
|
34
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'tilt/template'
|
2
|
+
require 'ox/builder'
|
3
|
+
|
4
|
+
module Tilt
|
5
|
+
class OxBuilderTemplate < Template
|
6
|
+
self.default_mime_type = 'text/xml'
|
7
|
+
|
8
|
+
def self.engine_initialized?
|
9
|
+
defined? ::Ox::Builder
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize_engine
|
13
|
+
require_template_library 'ox-builder'
|
14
|
+
end
|
15
|
+
|
16
|
+
def prepare
|
17
|
+
@code =<<-RUBY
|
18
|
+
Ox::Builder.build do
|
19
|
+
#{data}
|
20
|
+
end.to_xml
|
21
|
+
RUBY
|
22
|
+
end
|
23
|
+
|
24
|
+
def precompiled_template(locals)
|
25
|
+
@code
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/ox-builder.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |gem|
|
|
9
9
|
gem.authors = ["Daniel Vandersluis"]
|
10
10
|
gem.email = ["dvandersluis@selfmgmt.com"]
|
11
11
|
|
12
|
-
gem.summary = %q{
|
12
|
+
gem.summary = %q{DSL for easily building XML documents using ox}
|
13
13
|
gem.homepage = "https://www.github.com/dvandersluis/ox-builder"
|
14
14
|
gem.license = "MIT"
|
15
15
|
|
@@ -21,4 +21,12 @@ Gem::Specification.new do |gem|
|
|
21
21
|
gem.add_development_dependency "bundler", "~> 1.11"
|
22
22
|
gem.add_development_dependency "rake", "~> 10.0"
|
23
23
|
gem.add_development_dependency "rspec", "~> 3.0"
|
24
|
+
gem.add_development_dependency 'actionpack', ['~> 3.2']
|
25
|
+
gem.add_development_dependency 'activesupport', ['~> 3.2']
|
26
|
+
gem.add_development_dependency 'tilt', ['~> 1.4']
|
27
|
+
gem.add_development_dependency 'benchmark-ips'
|
28
|
+
gem.add_development_dependency 'builder'
|
29
|
+
|
30
|
+
gem.add_dependency 'ox', ['~> 2.3.0']
|
31
|
+
gem.add_dependency 'docile', ['~> 1.1.5']
|
24
32
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ox-builder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Vandersluis
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-04-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
type: :development
|
@@ -52,6 +52,104 @@ dependencies:
|
|
52
52
|
- - ~>
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
type: :development
|
57
|
+
prerelease: false
|
58
|
+
name: actionpack
|
59
|
+
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ~>
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '3.2'
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.2'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
name: activesupport
|
73
|
+
requirement: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '3.2'
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.2'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
type: :development
|
85
|
+
prerelease: false
|
86
|
+
name: tilt
|
87
|
+
requirement: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ~>
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '1.4'
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ~>
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.4'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
type: :development
|
99
|
+
prerelease: false
|
100
|
+
name: benchmark-ips
|
101
|
+
requirement: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ! '>='
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
type: :development
|
113
|
+
prerelease: false
|
114
|
+
name: builder
|
115
|
+
requirement: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - ! '>='
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ! '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
type: :runtime
|
127
|
+
prerelease: false
|
128
|
+
name: ox
|
129
|
+
requirement: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - ~>
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 2.3.0
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ~>
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 2.3.0
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
type: :runtime
|
141
|
+
prerelease: false
|
142
|
+
name: docile
|
143
|
+
requirement: !ruby/object:Gem::Requirement
|
144
|
+
requirements:
|
145
|
+
- - ~>
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: 1.1.5
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ~>
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 1.1.5
|
55
153
|
description:
|
56
154
|
email:
|
57
155
|
- dvandersluis@selfmgmt.com
|
@@ -62,14 +160,29 @@ files:
|
|
62
160
|
- .gitignore
|
63
161
|
- .rspec
|
64
162
|
- .travis.yml
|
163
|
+
- CHANGELOG.md
|
65
164
|
- Gemfile
|
66
165
|
- LICENSE.txt
|
67
166
|
- README.md
|
68
167
|
- Rakefile
|
168
|
+
- benchmarks/data/countries.yml
|
169
|
+
- benchmarks/huge.rb
|
170
|
+
- benchmarks/medium.rb
|
171
|
+
- benchmarks/runner.rb
|
172
|
+
- benchmarks/small.rb
|
173
|
+
- benchmarks/templates/large.builder
|
174
|
+
- benchmarks/templates/large.ox
|
175
|
+
- benchmarks/templates/small.builder
|
176
|
+
- benchmarks/templates/small.ox
|
69
177
|
- bin/console
|
70
178
|
- bin/setup
|
71
179
|
- lib/ox/builder.rb
|
180
|
+
- lib/ox/builder/action_view/template_handler.rb
|
181
|
+
- lib/ox/builder/dsl.rb
|
182
|
+
- lib/ox/builder/factory.rb
|
183
|
+
- lib/ox/builder/fallback_context_proxy.rb
|
72
184
|
- lib/ox/builder/version.rb
|
185
|
+
- lib/tilt/ox_builder_template.rb
|
73
186
|
- ox-builder.gemspec
|
74
187
|
homepage: https://www.github.com/dvandersluis/ox-builder
|
75
188
|
licenses:
|
@@ -94,6 +207,6 @@ rubyforge_project:
|
|
94
207
|
rubygems_version: 2.1.5
|
95
208
|
signing_key:
|
96
209
|
specification_version: 4
|
97
|
-
summary:
|
210
|
+
summary: DSL for easily building XML documents using ox
|
98
211
|
test_files: []
|
99
212
|
has_rdoc:
|