dress 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,152 @@
1
+ <h1
2
+ >XSLT(not!) with Elegant Dress</h1
3
+ ><p
4
+ >You'd swear XSLT is a joke, but it's not. It's cruelty. XSLT is like this: it's good to rid the city of this horrible vermin infestation-- Let's nuke the city. It's an out-of-proportion insanity. It's Turing-complete, and it's XML.</p
5
+ ><p
6
+ >Hmm.</p
7
+ ><p
8
+ >But what it is, is just a set of transformations on fragments of your XML document. The beauty of XSLT (they say), is that XSLT itself is XML, so you can (in principle) use XSLT to transform itself.</p
9
+ ><p
10
+ >Hmm.</p
11
+ ><p
12
+ >Oh I know, how about let's use Ruby?</p
13
+ ><h1
14
+ >Transformation Elegant Dress</h1
15
+ ><p
16
+ >Honestly, there's not much to it. A <code
17
+ >Dress</code
18
+ > is just a sequence of transformations you perform on a DOM tree. Unlike XSLT though, the transformations are performed directly on the DOM tree. That is to say, they are destructive.</p
19
+ ><p
20
+ >This is a simple dress,</p
21
+ ><pre
22
+ ><code
23
+ >require 'dress'
24
+ doc = &quot;&lt;my&gt;&lt;brain&gt;&lt;/brain&gt;&lt;/my&gt;&quot;
25
+ dress = Dress {
26
+ match(&quot;brain&quot;) do
27
+ set(&quot;size&quot;,&quot;pea&quot;)
28
+ end
29
+ }
30
+ result = dress.on(doc)
31
+ puts result.to_s
32
+ # &lt;my&gt;&lt;brain &quot;size&quot;=&quot;pea&quot;&gt;&lt;/brain&gt;&lt;/my&gt;
33
+ </code
34
+ ></pre
35
+ ><p
36
+ >We can have more matchers,</p
37
+ ><pre
38
+ ><code
39
+ >dress = Dress {
40
+ match(&quot;brain&quot;) do
41
+ set(&quot;size&quot;,&quot;pea&quot;)
42
+ end
43
+ match(&quot;my&quot;) do
44
+ each { |e| e.name = &quot;homer&quot;}
45
+ end
46
+ }
47
+ result = dress.on(doc)
48
+ puts result.to_s
49
+ # &lt;homer&gt;&lt;brain &quot;size&quot;=&quot;pea&quot;&gt;&lt;/brain&gt;&lt;/homer&gt;
50
+ </code
51
+ ></pre
52
+ ><p
53
+ >Note that match always yield a <code
54
+ >Nokogiri::Nodeset</code
55
+ >. But sometimes we'd like to operate on just one node (or the first one we find). For that there's the <code
56
+ >at</code
57
+ > matcher.</p
58
+ ><pre
59
+ ><code
60
+ >dress = Dress {
61
+ at(&quot;my&quot;) do
62
+ me.name = &quot;homer&quot;
63
+ end
64
+ }
65
+ </code
66
+ ></pre
67
+ ><p
68
+ ><code
69
+ >me</code
70
+ > is always the object yielded by the matcher string. For <code
71
+ >match</code
72
+ > it would be a Nodeset, and for <code
73
+ >at</code
74
+ >, it would be an Element.</p
75
+ ><p
76
+ >We can define helper methods on a Dress. This is one that implements a counter,</p
77
+ ><pre
78
+ ><code
79
+ >dress = Dress {
80
+ def count
81
+ @count ||= 0
82
+ @count += 1
83
+ @count
84
+ end
85
+
86
+ match(&quot;brain&quot;) do
87
+ each { |e| e[&quot;area&quot;] = count.to_s }
88
+ end
89
+ }
90
+ puts dress.on(Nokogiri.make { my { brain; brain; brain; brain }}).to_s
91
+ # &lt;my&gt;&lt;brain area=&quot;1&quot;&gt;&lt;/brain&gt;&lt;brain area=&quot;2&quot;&gt;&lt;/brain&gt;&lt;brain area=&quot;3&quot;&gt;&lt;/brain&gt;&lt;brain area=&quot;4&quot;&gt;&lt;/brain&gt;&lt;/my&gt;
92
+ </code
93
+ ></pre
94
+ ><p
95
+ >We can combine dresses into lines,</p
96
+ ><pre
97
+ ><code
98
+ >d1 = Dress { ... }
99
+ d2 = Dress { ... }
100
+ (d1 | d2).on(doc)
101
+ </code
102
+ ></pre
103
+ ><p
104
+ >We can link lines together,</p
105
+ ><pre
106
+ ><code
107
+ >d3 = Dress { ... }
108
+ d4 = Dress { ... }
109
+ ((d1 | d2) | (d3 | d4)).on(doc)
110
+ </code
111
+ ></pre
112
+ ><p
113
+ >A dress is a class inheriting from Dress.</p
114
+ ><pre
115
+ ><code
116
+ >class FancyDress &lt; Dress
117
+ def helper1
118
+ end
119
+ def helper2
120
+ end
121
+ match(...) { ... }
122
+ ...
123
+ end
124
+
125
+ class PrettyDress &lt; Dress
126
+ ...
127
+ end
128
+ </code
129
+ ></pre
130
+ ><p
131
+ >Then we can combine these dresses,</p
132
+ ><pre
133
+ ><code
134
+ >(FancyDress | PrettyDress).on(document)
135
+ </code
136
+ ></pre
137
+ ><p
138
+ >You can of course mix that with dynamic dresses,</p
139
+ ><pre
140
+ ><code
141
+ >(FancyDress | PrettyDress | Dress do ... end).on(doc)
142
+ </code
143
+ ></pre
144
+ ><h1
145
+ >That Wasn't So Hard, Was It?</h1
146
+ ><p
147
+ >So Ruby saved us all from XSLT. Minus all the XSLT-inspired buckets of tears, the world is a better place. FTW.</p
148
+ ><h1
149
+ >Copyright</h1
150
+ ><p
151
+ >Copyright (c) 2009 Howard Yeh. See LICENSE for details.</p
152
+ >
@@ -0,0 +1,139 @@
1
+ # XSLT(not!) with Elegant Dress
2
+
3
+ You'd swear XSLT is a joke, but it's not. It's
4
+ cruelty. XSLT is like this: it's good to rid the
5
+ city of this horrible vermin infestation-- Let's
6
+ nuke the city. It's an out-of-proportion
7
+ insanity. It's Turing-complete, and it's XML.
8
+
9
+ Hmm.
10
+
11
+ But what it is, is just a set of transformations
12
+ on fragments of your XML document. The beauty of
13
+ XSLT (they say), is that XSLT itself is XML, so
14
+ you can (in principle) use XSLT to transform
15
+ itself.
16
+
17
+ Hmm.
18
+
19
+ Oh I know, how about let's use Ruby?
20
+
21
+ # Transformation Elegant Dress
22
+
23
+ Honestly, there's not much to it. A `Dress` is
24
+ just a sequence of transformations you perform on
25
+ a DOM tree. Unlike XSLT though, the
26
+ transformations are performed directly on the DOM
27
+ tree. That is to say, they are destructive.
28
+
29
+ This is a simple dress,
30
+
31
+ require 'dress'
32
+ doc = "<my><brain></brain></my>"
33
+ dress = Dress {
34
+ match("brain") do
35
+ set("size","pea")
36
+ end
37
+ }
38
+ result = dress.on(doc)
39
+ puts result.to_s
40
+ # <my><brain "size"="pea"></brain></my>
41
+
42
+
43
+ We can have more matchers,
44
+
45
+ dress = Dress {
46
+ match("brain") do
47
+ set("size","pea")
48
+ end
49
+ match("my") do
50
+ each { |e| e.name = "homer"}
51
+ end
52
+ }
53
+ result = dress.on(doc)
54
+ puts result.to_s
55
+ # <homer><brain "size"="pea"></brain></homer>
56
+
57
+
58
+ Note that match always yield a
59
+ `Nokogiri::Nodeset`. But sometimes we'd like to
60
+ operate on just one node (or the first one we
61
+ find). For that there's the `at` matcher.
62
+
63
+ dress = Dress {
64
+ at("my") do
65
+ me.name = "homer"
66
+ end
67
+ }
68
+
69
+ `me` is always the object yielded by the matcher
70
+ string. For `match` it would be a Nodeset, and for
71
+ `at`, it would be an Element.
72
+
73
+ We can define helper methods on a Dress. This is
74
+ one that implements a counter,
75
+
76
+ dress = Dress {
77
+ def count
78
+ @count ||= 0
79
+ @count += 1
80
+ @count
81
+ end
82
+
83
+ match("brain") do
84
+ each { |e| e["area"] = count.to_s }
85
+ end
86
+ }
87
+ puts dress.on(Nokogiri.make { my { brain; brain; brain; brain }}).to_s
88
+ # <my><brain area="1"></brain><brain area="2"></brain><brain area="3"></brain><brain area="4"></brain></my>
89
+
90
+
91
+
92
+ We can combine dresses into lines,
93
+
94
+ d1 = Dress { ... }
95
+ d2 = Dress { ... }
96
+ (d1 | d2).on(doc)
97
+
98
+
99
+ We can link lines together,
100
+
101
+ d3 = Dress { ... }
102
+ d4 = Dress { ... }
103
+ ((d1 | d2) | (d3 | d4)).on(doc)
104
+
105
+
106
+ A dress is a class inheriting from Dress.
107
+
108
+ class FancyDress < Dress
109
+ def helper1
110
+ end
111
+ def helper2
112
+ end
113
+ match(...) { ... }
114
+ ...
115
+ end
116
+
117
+ class PrettyDress < Dress
118
+ ...
119
+ end
120
+
121
+
122
+ Then we can combine these dresses,
123
+
124
+ (FancyDress | PrettyDress).on(document)
125
+
126
+ You can of course mix that with dynamic dresses,
127
+
128
+ (FancyDress | PrettyDress | Dress do ... end).on(doc)
129
+
130
+
131
+ # That Wasn't So Hard, Was It?
132
+
133
+ So Ruby saved us all from XSLT. Minus all the
134
+ XSLT-inspired buckets of tears, the world is a
135
+ better place. FTW.
136
+
137
+ # Copyright
138
+
139
+ Copyright (c) 2009 Howard Yeh. See LICENSE for details.
File without changes
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ begin
5
5
  require 'jeweler'
6
6
  Jeweler::Tasks.new do |gem|
7
7
  gem.name = "dress"
8
- gem.summary = %Q{DOM transformation based on nokogiri}
8
+ gem.summary = %Q{DOM transformation based on Nokogiri}
9
9
  gem.description = %Q{Inspired by the horror of XSLT}
10
10
  gem.email = "hayeah@gmail.com"
11
11
  gem.homepage = "http://github.com/hayeah/dress"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.0.2
@@ -0,0 +1,57 @@
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{dress}
8
+ s.version = "0.0.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Howard Yeh"]
12
+ s.date = %q{2010-01-07}
13
+ s.description = %q{Inspired by the horror of XSLT}
14
+ s.email = %q{hayeah@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.html",
18
+ "README.markdown",
19
+ "README.textile"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ ".gitignore",
24
+ "LICENSE",
25
+ "README.markdown",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "dress.gemspec",
29
+ "lib/dress.rb",
30
+ "spec/dress_spec.rb",
31
+ "spec/spec.opts",
32
+ "spec/spec_helper.rb"
33
+ ]
34
+ s.homepage = %q{http://github.com/hayeah/dress}
35
+ s.rdoc_options = ["--charset=UTF-8"]
36
+ s.require_paths = ["lib"]
37
+ s.rubygems_version = %q{1.3.5}
38
+ s.summary = %q{DOM transformation based on Nokogiri}
39
+ s.test_files = [
40
+ "spec/dress_spec.rb",
41
+ "spec/spec_helper.rb"
42
+ ]
43
+
44
+ if s.respond_to? :specification_version then
45
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
46
+ s.specification_version = 3
47
+
48
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
49
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
50
+ else
51
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
52
+ end
53
+ else
54
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
55
+ end
56
+ end
57
+
@@ -90,3 +90,112 @@ end
90
90
  def Dress(&block)
91
91
  Dress.style(&block)
92
92
  end
93
+
94
+ # TODO move to monkey patch
95
+ class Nokogiri::XML::Builder
96
+ def n(*docs)
97
+ docs.each do |doc|
98
+ case doc
99
+ when String
100
+ self << doc
101
+ when Nokogiri::XML::Node
102
+ insert(doc)
103
+ #self << doc.to_s
104
+ #self.doc.children.each
105
+ else
106
+ raise "bad node: #{doc}"
107
+ end
108
+ end
109
+ end
110
+
111
+ def t(*texts)
112
+ texts.each do |text|
113
+ self.text(text.to_s)
114
+ self.text(" ")
115
+ end
116
+ end
117
+ end
118
+
119
+ class Dress::Maker
120
+ require 'active_support'
121
+ require 'active_support/core_ext'
122
+
123
+ class_inheritable_hash :layout_defs
124
+ self.layout_defs = {}
125
+
126
+ class << self
127
+
128
+
129
+ def layouts
130
+ #read_inheritable_attribute(:layouts).keys
131
+ layout_defs.keys
132
+ end
133
+
134
+ def layout(name=nil,&block)
135
+ layout_defs[name] = block
136
+ end
137
+
138
+ def with(name,page,*args,&block)
139
+ content = self.new.send(page,*args,&block)
140
+ l = layout(name).clone
141
+ l.at("content").replace(content)
142
+ l
143
+ end
144
+
145
+ def render(page,*args,&block)
146
+ self.new.render(page,*args,&block)
147
+ end
148
+
149
+ def render_with(layout,page,*args,&block)
150
+ self.new.render_with(layout,page,*args,&block)
151
+ end
152
+ end
153
+
154
+ def render(page,*args,&block)
155
+ # use default layout
156
+ render_with(nil,page,*args,&block)
157
+ end
158
+
159
+ def render_with(layout,page,*args,&block)
160
+ content = self.send(page,*args,&block)
161
+ l = self.instance_eval(&self.class.layout_defs[layout])
162
+ l.at("content").replace(content)
163
+ l
164
+ end
165
+
166
+ def method_missing(method,*args,&block)
167
+ Nokogiri.make {
168
+ #builder = self
169
+ d = self.send(method,*args,&block)
170
+ }
171
+ end
172
+ end
173
+
174
+ def DressMaker(&block)
175
+ c = Class.new(Dress::Maker)
176
+ c.class_eval(&block)
177
+ c
178
+ end
179
+
180
+
181
+ # TODO break this out to a separate loadable file
182
+ class Dress::ActiveView < Dress::Maker
183
+ require 'action_pack'
184
+ require 'action_view'
185
+ extend ActionView::Helpers
186
+ include ActionView::Helpers
187
+ DEFAULT_CONFIG = ActionView::DEFAULT_CONFIG unless defined?(DEFAULT_CONFIG)
188
+
189
+ def config
190
+ self.config = DEFAULT_CONFIG unless @config
191
+ @config
192
+ end
193
+
194
+ def config=(config)
195
+ @config = ActiveSupport::OrderedOptions.new.merge(config)
196
+ end
197
+
198
+ def initialize(controller)
199
+ @controller = controller
200
+ end
201
+ end
@@ -109,3 +109,39 @@ describe "Dress" do
109
109
  node.xpath("//bar/@b").map(&:value).should == ["2"]
110
110
  end
111
111
  end
112
+
113
+ describe "Dress::Maker" do
114
+ it "renders" do
115
+ d = DressMaker {
116
+ layout { n(wrapper_helper) }
117
+ layout(:foo) { foo { content }}
118
+
119
+ def content1
120
+ some_stuff(:a => "10", :b => "20") { inside }
121
+ end
122
+
123
+ def wrapper_helper
124
+ wrap1 { wrap2 { content }}
125
+ end
126
+ }
127
+ d.render(:content1).to_s.should == '<wrap1><wrap2><some_stuff a="10" b="20"><inside></inside></some_stuff></wrap2></wrap1>'
128
+ d.render_with(:foo,:content1).to_s.should == '<foo><some_stuff a="10" b="20"><inside></inside></some_stuff></foo>'
129
+ end
130
+
131
+ class D1 < Dress::Maker
132
+ layout { foo { content }}
133
+ end
134
+
135
+ class D2 < D1
136
+ def bar
137
+ "bar"
138
+ end
139
+ end
140
+
141
+ it "inherit layouts" do
142
+ #p D1.layout_defs
143
+ #p D2.layout_defs
144
+ D2.layouts.should_not be_empty
145
+ #D1.render(:bar)
146
+ end
147
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dress
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Howard Yeh
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-11-28 00:00:00 -08:00
12
+ date: 2010-01-07 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -30,18 +30,23 @@ extensions: []
30
30
 
31
31
  extra_rdoc_files:
32
32
  - LICENSE
33
- - README
33
+ - README.html
34
+ - README.markdown
35
+ - README.textile
34
36
  files:
35
37
  - .document
36
38
  - .gitignore
37
39
  - LICENSE
38
- - README
40
+ - README.markdown
39
41
  - Rakefile
40
42
  - VERSION
43
+ - dress.gemspec
41
44
  - lib/dress.rb
42
45
  - spec/dress_spec.rb
43
46
  - spec/spec.opts
44
47
  - spec/spec_helper.rb
48
+ - README.html
49
+ - README.textile
45
50
  has_rdoc: true
46
51
  homepage: http://github.com/hayeah/dress
47
52
  licenses: []
@@ -69,7 +74,7 @@ rubyforge_project:
69
74
  rubygems_version: 1.3.5
70
75
  signing_key:
71
76
  specification_version: 3
72
- summary: DOM transformation based on nokogiri
77
+ summary: DOM transformation based on Nokogiri
73
78
  test_files:
74
79
  - spec/dress_spec.rb
75
80
  - spec/spec_helper.rb