excesselt 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +56 -0
- data/History.txt +4 -0
- data/PostInstall.txt +1 -0
- data/README.md +67 -0
- data/Rakefile +54 -0
- data/TODO +3 -0
- data/excesselt.gemspec +102 -0
- data/lib/excesselt/element_wrapper.rb +37 -0
- data/lib/excesselt/rule.rb +45 -0
- data/lib/excesselt/stylesheet.rb +64 -0
- data/lib/excesselt.rb +9 -0
- data/rdoc/classes/Excesselt/ElementWrapper.html +276 -0
- data/rdoc/classes/Excesselt/Rule.html +290 -0
- data/rdoc/classes/Excesselt/Stylesheet.html +242 -0
- data/rdoc/classes/Excesselt.html +138 -0
- data/rdoc/created.rid +1 -0
- data/rdoc/files/README_md.html +199 -0
- data/rdoc/files/lib/excesselt/element_wrapper_rb.html +101 -0
- data/rdoc/files/lib/excesselt/rule_rb.html +101 -0
- data/rdoc/files/lib/excesselt/stylesheet_rb.html +108 -0
- data/rdoc/files/lib/excesselt_rb.html +110 -0
- data/rdoc/fr_class_index.html +30 -0
- data/rdoc/fr_file_index.html +31 -0
- data/rdoc/fr_method_index.html +40 -0
- data/rdoc/index.html +24 -0
- data/rdoc/rdoc-style.css +208 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/spec/excesselt_spec.rb +90 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/support/matchers/dom_matcher.rb +45 -0
- data/tasks/rspec.rake +10 -0
- metadata +227 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
excesselt (1.0.0)
|
5
|
+
builder (= 2.1.2)
|
6
|
+
nokogiri (= 1.4.3.1)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
activesupport (3.0.1)
|
12
|
+
builder (2.1.2)
|
13
|
+
columnize (0.3.1)
|
14
|
+
diff-lcs (1.1.2)
|
15
|
+
gemcutter (0.6.1)
|
16
|
+
git (1.2.5)
|
17
|
+
jeweler (1.4.0)
|
18
|
+
gemcutter (>= 0.1.0)
|
19
|
+
git (>= 1.2.5)
|
20
|
+
rubyforge (>= 2.0.0)
|
21
|
+
json_pure (1.4.6)
|
22
|
+
linecache (0.43)
|
23
|
+
nokogiri (1.4.3.1)
|
24
|
+
rake (0.8.7)
|
25
|
+
rcov (0.9.9)
|
26
|
+
rspec (2.0.1)
|
27
|
+
rspec-core (~> 2.0.1)
|
28
|
+
rspec-expectations (~> 2.0.1)
|
29
|
+
rspec-mocks (~> 2.0.1)
|
30
|
+
rspec-core (2.0.1)
|
31
|
+
rspec-expectations (2.0.1)
|
32
|
+
diff-lcs (>= 1.1.2)
|
33
|
+
rspec-mocks (2.0.1)
|
34
|
+
rspec-core (~> 2.0.1)
|
35
|
+
rspec-expectations (~> 2.0.1)
|
36
|
+
ruby-debug (0.10.3)
|
37
|
+
columnize (>= 0.1)
|
38
|
+
ruby-debug-base (~> 0.10.3.0)
|
39
|
+
ruby-debug-base (0.10.3)
|
40
|
+
linecache (>= 0.3)
|
41
|
+
rubyforge (2.0.4)
|
42
|
+
json_pure (>= 1.1.7)
|
43
|
+
|
44
|
+
PLATFORMS
|
45
|
+
ruby
|
46
|
+
|
47
|
+
DEPENDENCIES
|
48
|
+
activesupport
|
49
|
+
builder (= 2.1.2)
|
50
|
+
excesselt!
|
51
|
+
jeweler
|
52
|
+
nokogiri (= 1.4.3.1)
|
53
|
+
rake
|
54
|
+
rcov
|
55
|
+
rspec (> 2.0.0)
|
56
|
+
ruby-debug
|
data/History.txt
ADDED
data/PostInstall.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
You're ready to get rid of that awful XSLT stuck in your codebase!
|
data/README.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Excesselt
|
2
|
+
|
3
|
+
http://github.com/DanielHeath/excesselt
|
4
|
+
|
5
|
+
## DESCRIPTION:
|
6
|
+
|
7
|
+
Excesselt is a ruby library that I built because I hate XSLT.
|
8
|
+
|
9
|
+
I've extracted it from an app I built for my work at Lonely Planet.
|
10
|
+
|
11
|
+
Excesselt solves the same problem as XSLT does (that is, how can I transform this xml document into some other format).
|
12
|
+
|
13
|
+
## FEATURES/PROBLEMS:
|
14
|
+
|
15
|
+
Nice syntax.
|
16
|
+
Testable, reusable xml transformation
|
17
|
+
Tested on REE 1.8.7 - TODO test on more platforms and update this section
|
18
|
+
|
19
|
+
## SYNOPSIS:
|
20
|
+
|
21
|
+
class MyStylesheet < Excesselt::Stylesheet
|
22
|
+
def rules
|
23
|
+
render('parent > child') { builder.p(:style => "child_content" ) { child_content } }
|
24
|
+
render('parent') { builder.p(:style => "parent_content") { child_content } }
|
25
|
+
render('text()') { add element.to_xml.upcase }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
MyStylesheet.transform <<-XML
|
30
|
+
<parent>
|
31
|
+
<child>Use Excesselt</child>
|
32
|
+
</parent>
|
33
|
+
XML
|
34
|
+
-> <p style="parent_content"><p style="child_content">USE EXCESSELT</p></p>
|
35
|
+
|
36
|
+
## REQUIREMENTS:
|
37
|
+
|
38
|
+
* Nokogiri, Builder
|
39
|
+
|
40
|
+
## INSTALL:
|
41
|
+
|
42
|
+
* gem install excesselt
|
43
|
+
|
44
|
+
## LICENSE:
|
45
|
+
|
46
|
+
(The MIT License)
|
47
|
+
|
48
|
+
Copyright (c) 2010 Daniel Heath
|
49
|
+
|
50
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
51
|
+
a copy of this software and associated documentation files (the
|
52
|
+
'Software'), to deal in the Software without restriction, including
|
53
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
54
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
55
|
+
permit persons to whom the Software is furnished to do so, subject to
|
56
|
+
the following conditions:
|
57
|
+
|
58
|
+
The above copyright notice and this permission notice shall be
|
59
|
+
included in all copies or substantial portions of the Software.
|
60
|
+
|
61
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
62
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
63
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
64
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
65
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
66
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
67
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
begin
|
3
|
+
Bundler.setup(:default, :development)
|
4
|
+
Bundler::GemHelper.install_tasks
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'jeweler'
|
12
|
+
require 'excesselt'
|
13
|
+
Jeweler::Tasks.new do |s|
|
14
|
+
s.platform = Gem::Platform::RUBY
|
15
|
+
s.name = 'excesselt'
|
16
|
+
s.version = Excesselt::VERSION
|
17
|
+
s.summary = 'Helps you to transform XML without using XSLT.'
|
18
|
+
s.description = 'I had a lot of XML transformation to do and the requirements kept changing, so I sat down and wrote something that was easy to modify.'
|
19
|
+
|
20
|
+
s.required_ruby_version = '>= 1.8.7'
|
21
|
+
s.required_rubygems_version = ">= 1.3.6"
|
22
|
+
|
23
|
+
s.author = 'Daniel Heath'
|
24
|
+
s.email = 'daniel.r.heath@gmail.com'
|
25
|
+
s.homepage = 'http://www.github.com/danielheath/excesselt'
|
26
|
+
|
27
|
+
# Would be good to take a stylesheet and an xml file as arguments for a binary.
|
28
|
+
# s.bindir = 'bin'
|
29
|
+
# s.executables = ['excesselt']
|
30
|
+
# s.default_executable = 'excesselt'
|
31
|
+
|
32
|
+
s.rdoc_options = ["--charset=UTF-8", "-mREADME.md"]
|
33
|
+
|
34
|
+
s.add_dependency('nokogiri', '1.4.3.1')
|
35
|
+
s.add_dependency('builder', '2.1.2')
|
36
|
+
s.add_development_dependency('activesupport')
|
37
|
+
s.add_development_dependency('rake')
|
38
|
+
s.add_development_dependency('rspec', '>2.0.0')
|
39
|
+
s.add_development_dependency('rcov')
|
40
|
+
s.add_development_dependency('ruby-debug')
|
41
|
+
s.add_development_dependency('jeweler')
|
42
|
+
end
|
43
|
+
|
44
|
+
require 'rake/rdoctask'
|
45
|
+
Rake::RDocTask.new do |rdoc|
|
46
|
+
version = Excesselt::VERSION
|
47
|
+
rdoc.main = "README.md"
|
48
|
+
rdoc.rdoc_dir = 'rdoc'
|
49
|
+
rdoc.title = "<%= project_name %> #{version}"
|
50
|
+
rdoc.rdoc_files.include('README.md')
|
51
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
52
|
+
end
|
53
|
+
|
54
|
+
Dir.glob('tasks/*').each {|rakefile| load rakefile }
|
data/excesselt.gemspec
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{excesselt}
|
8
|
+
s.version = "1.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.3.6") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Daniel Heath"]
|
12
|
+
s.date = %q{2010-11-08}
|
13
|
+
s.description = %q{I had a lot of XML transformation to do and the requirements kept changing, so I sat down and wrote something that was easy to modify.}
|
14
|
+
s.email = %q{daniel.r.heath@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.md",
|
17
|
+
"TODO"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".gitignore",
|
21
|
+
"Gemfile",
|
22
|
+
"Gemfile.lock",
|
23
|
+
"History.txt",
|
24
|
+
"PostInstall.txt",
|
25
|
+
"README.md",
|
26
|
+
"Rakefile",
|
27
|
+
"TODO",
|
28
|
+
"excesselt.gemspec",
|
29
|
+
"lib/excesselt.rb",
|
30
|
+
"lib/excesselt/element_wrapper.rb",
|
31
|
+
"lib/excesselt/rule.rb",
|
32
|
+
"lib/excesselt/stylesheet.rb",
|
33
|
+
"rdoc/classes/Excesselt.html",
|
34
|
+
"rdoc/classes/Excesselt/ElementWrapper.html",
|
35
|
+
"rdoc/classes/Excesselt/Rule.html",
|
36
|
+
"rdoc/classes/Excesselt/Stylesheet.html",
|
37
|
+
"rdoc/created.rid",
|
38
|
+
"rdoc/files/README_md.html",
|
39
|
+
"rdoc/files/lib/excesselt/element_wrapper_rb.html",
|
40
|
+
"rdoc/files/lib/excesselt/rule_rb.html",
|
41
|
+
"rdoc/files/lib/excesselt/stylesheet_rb.html",
|
42
|
+
"rdoc/files/lib/excesselt_rb.html",
|
43
|
+
"rdoc/fr_class_index.html",
|
44
|
+
"rdoc/fr_file_index.html",
|
45
|
+
"rdoc/fr_method_index.html",
|
46
|
+
"rdoc/index.html",
|
47
|
+
"rdoc/rdoc-style.css",
|
48
|
+
"script/console",
|
49
|
+
"script/destroy",
|
50
|
+
"script/generate",
|
51
|
+
"spec/excesselt_spec.rb",
|
52
|
+
"spec/spec_helper.rb",
|
53
|
+
"spec/support/matchers/dom_matcher.rb",
|
54
|
+
"tasks/rspec.rake"
|
55
|
+
]
|
56
|
+
s.homepage = %q{http://www.github.com/danielheath/excesselt}
|
57
|
+
s.rdoc_options = ["--charset=UTF-8", "-mREADME.md"]
|
58
|
+
s.require_paths = ["lib"]
|
59
|
+
s.required_ruby_version = Gem::Requirement.new(">= 1.8.7")
|
60
|
+
s.rubygems_version = %q{1.3.7}
|
61
|
+
s.summary = %q{Helps you to transform XML without using XSLT.}
|
62
|
+
s.test_files = [
|
63
|
+
"spec/excesselt_spec.rb",
|
64
|
+
"spec/spec_helper.rb",
|
65
|
+
"spec/support/matchers/dom_matcher.rb"
|
66
|
+
]
|
67
|
+
|
68
|
+
if s.respond_to? :specification_version then
|
69
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
70
|
+
s.specification_version = 3
|
71
|
+
|
72
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
73
|
+
s.add_runtime_dependency(%q<nokogiri>, ["= 1.4.3.1"])
|
74
|
+
s.add_runtime_dependency(%q<builder>, ["= 2.1.2"])
|
75
|
+
s.add_development_dependency(%q<activesupport>, [">= 0"])
|
76
|
+
s.add_development_dependency(%q<rake>, [">= 0"])
|
77
|
+
s.add_development_dependency(%q<rspec>, ["> 2.0.0"])
|
78
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
79
|
+
s.add_development_dependency(%q<ruby-debug>, [">= 0"])
|
80
|
+
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
81
|
+
else
|
82
|
+
s.add_dependency(%q<nokogiri>, ["= 1.4.3.1"])
|
83
|
+
s.add_dependency(%q<builder>, ["= 2.1.2"])
|
84
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
85
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
86
|
+
s.add_dependency(%q<rspec>, ["> 2.0.0"])
|
87
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
88
|
+
s.add_dependency(%q<ruby-debug>, [">= 0"])
|
89
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
90
|
+
end
|
91
|
+
else
|
92
|
+
s.add_dependency(%q<nokogiri>, ["= 1.4.3.1"])
|
93
|
+
s.add_dependency(%q<builder>, ["= 2.1.2"])
|
94
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
95
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
96
|
+
s.add_dependency(%q<rspec>, ["> 2.0.0"])
|
97
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
98
|
+
s.add_dependency(%q<ruby-debug>, [">= 0"])
|
99
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Excesselt
|
2
|
+
class ElementWrapper
|
3
|
+
|
4
|
+
attr_reader :element, :builder, :stylesheet
|
5
|
+
|
6
|
+
def initialize(stylesheet, element, builder)
|
7
|
+
@stylesheet = stylesheet
|
8
|
+
@element = element
|
9
|
+
@builder = builder
|
10
|
+
end
|
11
|
+
|
12
|
+
def child_content(selector=nil)
|
13
|
+
elements = selector ? @element.css(selector) : @element.children
|
14
|
+
elements.each do |child|
|
15
|
+
stylesheet.generate_element(child)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def method_missing(sym, *args)
|
20
|
+
begin
|
21
|
+
@element.send(sym, *args)
|
22
|
+
rescue Exception => e
|
23
|
+
raise e.exception("Error delegating method '#{sym}' to #{@element.class.name}: #{e.message}\n\n#{e.backtrace.join("\n")}")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def add(*content)
|
28
|
+
@builder << content.join('')
|
29
|
+
end
|
30
|
+
|
31
|
+
def error(string)
|
32
|
+
stylesheet.errors << string
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Excesselt
|
2
|
+
class Rule
|
3
|
+
|
4
|
+
attr_reader :stylesheet, :element, :block, :selector
|
5
|
+
|
6
|
+
def initialize(stylesheet, selector, extensions, &block)
|
7
|
+
@stylesheet = stylesheet
|
8
|
+
@selector = selector
|
9
|
+
@extensions = extensions
|
10
|
+
@block = block
|
11
|
+
end
|
12
|
+
|
13
|
+
def matching_elements(document)
|
14
|
+
@selector_cache ||= {}
|
15
|
+
@selector_cache[document] ||= document.css(@selector)
|
16
|
+
end
|
17
|
+
|
18
|
+
def applies_to_element?
|
19
|
+
matching_elements(element.document).include? element
|
20
|
+
end
|
21
|
+
|
22
|
+
def matches?(element)
|
23
|
+
@element = element
|
24
|
+
if applies_to_element?
|
25
|
+
self # if it matches, nil otherwise
|
26
|
+
else
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def generate(builder)
|
32
|
+
# Call the block in the elements context
|
33
|
+
wrapper = ElementWrapper.new(stylesheet, element, builder)
|
34
|
+
@extensions.each {|e| wrapper.extend e }
|
35
|
+
wrapper.instance_eval(&@block)
|
36
|
+
rescue Exception => e
|
37
|
+
if e.message =~ /With Included Modules/
|
38
|
+
raise e
|
39
|
+
else
|
40
|
+
raise e.class, "With Included Modules: #{@extensions.inspect}\n#{e.message}\n#{e.backtrace.join("\n")}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'builder'
|
2
|
+
module Excesselt
|
3
|
+
class Stylesheet
|
4
|
+
|
5
|
+
attr_reader :builder, :errors
|
6
|
+
|
7
|
+
def self.transform(xml)
|
8
|
+
self.new.transform(xml)
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@builder = Builder::XmlMarkup.new
|
13
|
+
@helper_modules = []
|
14
|
+
@errors = []
|
15
|
+
end
|
16
|
+
|
17
|
+
def transform(xml)
|
18
|
+
generate_element(Nokogiri::XML(xml, nil, nil, Nokogiri::XML::ParseOptions.new).root)
|
19
|
+
end
|
20
|
+
|
21
|
+
def generate_element(element)
|
22
|
+
rule = rule_for(element)
|
23
|
+
raise "Attempted to generate #{self.name} with parents #{self.parents.inspect} but no rule was found." unless rule
|
24
|
+
rule.generate(builder)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def rule_for(element)
|
30
|
+
# Look up the rule that is used to render this.
|
31
|
+
# Should fold into stylesheet.rules (collection) .find(:matches?, element)
|
32
|
+
# TODO: Patch enumerable#find etc to take a plain symbol and some arguments?
|
33
|
+
rule = get_rules.find {|rule| rule.matches? element }
|
34
|
+
rule or raise "There is no style defined to handle element #{element.node.name} in this context (element.node.parents.inspect)"
|
35
|
+
end
|
36
|
+
|
37
|
+
def helper(*mods, &block)
|
38
|
+
@helper_modules.push(mods).flatten!
|
39
|
+
block.call
|
40
|
+
@helper_modules -= [mods].flatten
|
41
|
+
end
|
42
|
+
|
43
|
+
def render(selector, opts={}, &block)
|
44
|
+
raise "Neither a block nor a :with option were provided for '#{selector}'" unless (opts[:with] or block)
|
45
|
+
|
46
|
+
mappings << Rule.new(self, selector, @helper_modules) do
|
47
|
+
opts[:with] ? self.send(opts[:with]) : (instance_eval &block)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def mappings
|
52
|
+
@mappings ||= []
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_rules
|
56
|
+
unless @rules_generated
|
57
|
+
rules # Generates the mappings
|
58
|
+
@rules_generated = true
|
59
|
+
end
|
60
|
+
mappings
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
data/lib/excesselt.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
2
|
+
|
3
|
+
module Excesselt
|
4
|
+
VERSION = '1.0.0'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'excesselt/stylesheet'
|
8
|
+
require 'excesselt/rule'
|
9
|
+
require 'excesselt/element_wrapper'
|