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.
@@ -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
@@ -0,0 +1,6 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+
3
+ require 'benchmark/ips'
4
+ require 'builder'
5
+ require 'tilt'
6
+ require 'ox/builder'
@@ -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
@@ -0,0 +1,7 @@
1
+ xml.instruct!
2
+
3
+ xml.person id: 123 do
4
+ xml.name { xml.cdata!('John Smith') }
5
+ xml.age 37
6
+ xml.nationality 'Canadian'
7
+ end
@@ -0,0 +1,7 @@
1
+ instruct!
2
+
3
+ person id: 123 do
4
+ name { cdata!('John Smith') }
5
+ age 37
6
+ nationality 'Canadian'
7
+ 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
@@ -1,5 +1,5 @@
1
1
  module Ox
2
2
  module Builder
3
- VERSION = "0.1.0"
3
+ VERSION = "1.0.1"
4
4
  end
5
5
  end
data/lib/ox/builder.rb CHANGED
@@ -1,7 +1,34 @@
1
- require "ox/builder/version"
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
- # Your code goes here...
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{XML Builder for Rails using ox}
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.0
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-03-30 00:00:00.000000000 Z
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: XML Builder for Rails using ox
210
+ summary: DSL for easily building XML documents using ox
98
211
  test_files: []
99
212
  has_rdoc: