matryoshka 0.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,18 @@
1
+ Manifest
2
+ Rakefile
3
+ config.ru
4
+ lib/matryoshka.rb
5
+ lib/matryoshka/answer.rb
6
+ lib/matryoshka/data.rb
7
+ lib/matryoshka/document.rb
8
+ lib/matryoshka/document/delegate.rb
9
+ lib/matryoshka/document/html.rb
10
+ lib/matryoshka/document/html/merge.rb
11
+ lib/matryoshka/document/unknown.rb
12
+ lib/matryoshka/external.rb
13
+ public/README
14
+ templates/image.jpg
15
+ templates/index.html
16
+ templates/proxy/index.html
17
+ templates/test/about.html
18
+ templates/test/index.html
@@ -0,0 +1,15 @@
1
+ # Rakefile
2
+ require 'rubygems'
3
+ require 'rake'
4
+ require 'echoe'
5
+
6
+ Echoe.new('matryoshka', '0.0.1') do |p|
7
+ p.description = "Rack middleware for parsing html templates."
8
+ p.url = "http://samsm.com/"
9
+ p.author = "Sam Schenkman-Moore"
10
+ p.email = "samsm@samsm.com"
11
+ p.ignore_pattern = ["tmp/*", "script/*"]
12
+ p.development_dependencies = ['hpricot']
13
+ end
14
+
15
+ Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
@@ -0,0 +1,7 @@
1
+ # config.ru
2
+ require 'rubygems'
3
+ require 'rack'
4
+ require 'lib/matryoshka'
5
+
6
+ use Rack::ShowExceptions
7
+ run Matryoshka.new
@@ -0,0 +1,33 @@
1
+ class Matryoshka
2
+ ROOT_DIR = File.expand_path(File.dirname(__FILE__) + '/../')
3
+
4
+ def self.mrequire(filename)
5
+ Kernel.require ROOT_DIR + "/lib/matryoshka/#{filename}"
6
+ end
7
+ end
8
+
9
+ Matryoshka.mrequire 'answer'
10
+ Matryoshka.mrequire 'data'
11
+ Matryoshka.mrequire 'document'
12
+ Matryoshka.mrequire 'document/delegate'
13
+ Matryoshka.mrequire 'document/html'
14
+ Matryoshka.mrequire 'document/html/merge'
15
+ Matryoshka.mrequire 'document/unknown'
16
+ Matryoshka.mrequire 'external'
17
+
18
+
19
+ class Matryoshka
20
+ def initialize(app = nil)
21
+ @application = app
22
+ end
23
+
24
+ def application
25
+ @application
26
+ end
27
+
28
+ def call(rack_env)
29
+ # puts rack_env['REQUEST_URI']
30
+ Answer.new(rack_env, application).to_rack
31
+ end
32
+
33
+ end
@@ -0,0 +1,158 @@
1
+ class Matryoshka::Answer
2
+
3
+ attr_accessor :env, :chained_application, :data
4
+
5
+ def initialize(rack_env, chained_application)
6
+ self.env = rack_env
7
+ self.chained_application = chained_application
8
+
9
+ self.data = Matryoshka::Data.new(env['HTTP_HOST'])
10
+ end
11
+
12
+ def requested_page
13
+ @requested_page ||=
14
+ if chained_application # Rails or other Framework handles page
15
+ handler.new(chained_application.call(env))
16
+ else
17
+ local_template or
18
+ proxy_template or
19
+ not_found_template
20
+ end
21
+ end
22
+
23
+ def local_template
24
+ return false unless template = load_template(path_with_index)
25
+ if template.proxy?
26
+ context_templates << template
27
+ proxy_template
28
+ else
29
+ template
30
+ end
31
+
32
+ end
33
+
34
+ def proxy_template
35
+ top_context_template = context_templates.last
36
+ if (top_context_template and top_context_template.proxy?)
37
+ proxy = top_context_template.prepare_proxy(path)
38
+ proxy
39
+ end
40
+ end
41
+
42
+ def not_found_template
43
+ # For now ...
44
+ handler.new [404,{},'<div id="content">404\'d!</div>']
45
+ end
46
+
47
+ def to_rack
48
+ # can we handle this request? if not, just pass it along
49
+ return requested_page.call(env) unless matryoshkable?
50
+
51
+ # gather the files necessary for this request
52
+ # merge them together
53
+ # merged_context # referenced below
54
+ requested_page
55
+
56
+ result = if merged_context
57
+ merge(merged_context, requested_page)
58
+ else
59
+ requested_page
60
+ end
61
+
62
+ result.call(env)
63
+ end
64
+
65
+ def path
66
+ env['REQUEST_URI']
67
+ end
68
+
69
+ def path_without_extention
70
+ path.sub(/\.\w+\Z/,'')
71
+ end
72
+
73
+ def path_with_index
74
+ if path[/\/\Z/] # path ends with /
75
+ path + 'index'
76
+ else
77
+ path
78
+ end
79
+ end
80
+
81
+ def merge(a,b)
82
+ handler.new [
83
+ b.status,
84
+ b.headers,
85
+ handler::Merge.new(a,b).run
86
+ ]
87
+ end
88
+
89
+ def merged_context
90
+ @merged_context ||=
91
+ context_templates.inject do |result, template|
92
+ result = merge(result,template)
93
+ end
94
+ end
95
+
96
+ def context_paths(path_to_context_array = path)
97
+ segments = path_to_context_array.split('/')
98
+
99
+ # Remove the last element (the requested page)
100
+ # Empty array only happens on '/'. No context. Shortcut out.
101
+ return [] unless segments.pop
102
+
103
+ paths = []
104
+
105
+ # ['',1,2,3] becomes ['/','/1','/1/2','/1/2/3']
106
+ segments.each_with_index do |segment,index|
107
+ paths << segments[0..index].join('/')
108
+ end
109
+
110
+ paths # paths.collect {|p| p + '/index.html'}
111
+ end
112
+
113
+ # Get file_data and full_path from here for a given context
114
+ def context_templates(opts = {})
115
+ return @context_templates if @context_templates
116
+ options = {:path_array => context_paths,
117
+ :file_name => 'index',
118
+ :current_handler => handler}.merge(opts)
119
+ path_array = options[:path_array]
120
+ @context_templates = path_array.collect do |p|
121
+ unless "#{p}/#{options[:file_name]}" == path_without_extention
122
+ load_template("#{p}/#{options[:file_name]}", options[:current_handler])
123
+ end
124
+ end.compact
125
+ end
126
+
127
+ # The request path, and the current handler
128
+ def load_template(extention_optional_path,current_handler = handler)
129
+ rack_arr = data.find extention_optional_path, current_handler.extentions
130
+ if rack_arr
131
+ current_handler.new(rack_arr)
132
+ end
133
+ end
134
+
135
+ def handler
136
+ matryoshka_handler or fallback_handler
137
+ end
138
+
139
+ def matryoshkable?
140
+ matryoshka_handler
141
+ end
142
+
143
+ def matryoshka_handler
144
+ # handler = Matryoshka::Document.detect_handler(@env)
145
+ # handler.new(nil) if handler
146
+ Matryoshka::Document.detect_handler(env)
147
+ end
148
+
149
+ # This is for when a request makes it here, but cannot be handled.
150
+ def fallback_handler
151
+ Matryoshka::Document::Unknown
152
+ end
153
+
154
+ def delegate_handler
155
+ Matryoshka::Document::Delegate
156
+ end
157
+
158
+ end
@@ -0,0 +1,41 @@
1
+ class Matryoshka::Data
2
+ def initialize(*args)
3
+ # args = whatever is necessary to find correct dir
4
+ # Right now that means nothing
5
+ end
6
+
7
+ def expand(path)
8
+ if File.directory?('./templates')
9
+ './templates' + path
10
+ else
11
+ Matryoshka::ROOT_DIR + '/templates' + path
12
+ end
13
+ end
14
+
15
+ def find(path, extentions = [''])
16
+ path = strip_extention(path)
17
+ extentions.each do |extention|
18
+ path_with_extention = "#{path}#{extention}"
19
+ if exists? path_with_extention
20
+ return [200,
21
+ {:template_path => path_with_extention },
22
+ read(path_with_extention)
23
+ ]
24
+ end
25
+ end
26
+ false # No results found.
27
+ end
28
+
29
+ def read(path_with_extention)
30
+ IO.read(expand(path_with_extention))
31
+ end
32
+
33
+ def exists?(path)
34
+ File.exists? expand(path)
35
+ end
36
+
37
+ # This may not be smart.
38
+ def strip_extention(path)
39
+ path.sub(/\.[^.]{1,4}\Z/,'')
40
+ end
41
+ end
@@ -0,0 +1,41 @@
1
+ module Matryoshka::Document
2
+
3
+ def self.detect_handler(env)
4
+
5
+ accepts_header = env['HTTP_ACCEPT']
6
+ request_path = env['REQUEST_URI']
7
+
8
+ detect_using_extention(request_path) or
9
+ detect_using_accepts(accepts_header)
10
+
11
+ end
12
+
13
+ def self.detect(method,matcher)
14
+ document_classes.each do |klass|
15
+ klass.send(method).each do |detection_test|
16
+ if matcher =~ Regexp.new(Regexp.escape(detection_test))
17
+ return klass
18
+ end
19
+ end
20
+ end
21
+
22
+ # nothing matched, so ...
23
+ false
24
+ end
25
+
26
+ def self.detect_using_extention(path)
27
+ detect :extentions, File.extname(path)
28
+ end
29
+
30
+ def self.detect_using_accepts(accepts_header)
31
+ detect :accepts, accepts_header
32
+ end
33
+
34
+ def self.document_classes
35
+ constants.collect do |const|
36
+ klass = const_get(const)
37
+ klass if klass.kind_of?(Class)
38
+ end.compact
39
+ end
40
+
41
+ end
@@ -0,0 +1,19 @@
1
+ class Matryoshka::Document::Delegate
2
+ attr_accessor :application
3
+
4
+ def initialize(app)
5
+ self.application = app
6
+ end
7
+
8
+ def call(env)
9
+ application.class(env)
10
+ end
11
+
12
+ def self.extentions
13
+ []
14
+ end
15
+
16
+ def self.accepts
17
+ []
18
+ end
19
+ end
@@ -0,0 +1,171 @@
1
+ gem 'hpricot'
2
+ require 'hpricot'
3
+
4
+ class Matryoshka::Document::Html
5
+
6
+ attr_accessor :body, :content, :path, :status, :headers
7
+
8
+ def externals_loaded?
9
+ @externals_loaded
10
+ end
11
+
12
+ def proxy_loaded?
13
+ @proxy_loaded
14
+ end
15
+
16
+ EXTERNAL_SEARCH_PATTERN = '[@rel="external"]'
17
+ PROXY_SEARCH_PATTERN = '[@rel="proxy"]'
18
+
19
+ def proxy?
20
+ content.at PROXY_SEARCH_PATTERN
21
+ end
22
+
23
+ def prepare_proxy(full_request_path = '')
24
+ element = content.at PROXY_SEARCH_PATTERN
25
+ proxy_link = if full_request_path == @headers[:template_path]
26
+ element[:href]
27
+ else
28
+ closest_directory(element[:href]) +
29
+ full_request_path.sub(/\A#{closest_directory(@headers[:template_path])}/,'')
30
+ end
31
+
32
+ # Need to prime external with template_path
33
+ external = self.class.new(Matryoshka::External.find(proxy_link, {:template_path => @headers[:template_path]}))
34
+ # external.make_links_absolute(element[:href])
35
+ base_dir = closest_directory(element[:href])
36
+
37
+ # if doc is not a full (<html><head> ...) don't bother with transform?
38
+
39
+ # merge the external with a copy of the element
40
+ # convoluted copy element (.dup is weird with Hpricot)
41
+ element_copy = Hpricot(element.to_html).at '*'
42
+ external.content = Merge.new(element_copy,external.content,Merge::EXTERNAL_MERGE).run
43
+ external.convert_proxy_links(base_dir)
44
+ external.make_links_absolute(base_dir,{'img'=>'src'})
45
+
46
+ # Tag the element and the proxy doc so that they cleanly merge.
47
+ # This is to keep the pattern established in answer.rb
48
+ element.set_attribute('id', 'matryoshka_proxy_target')
49
+ external.content.set_attribute('id','matryoshka_proxy_target')
50
+ external
51
+ end
52
+
53
+ def closest_directory(path)
54
+ path[/\A.+\//]
55
+ end
56
+
57
+ def convert_proxy_links(proxy_base)
58
+ (content/'a').each do |link|
59
+ href = link.attributes['href']
60
+
61
+ # Remove base of urls that we are proxying.
62
+ href.sub!(/\A#{proxy_base}/,'')
63
+
64
+ # Except for absolute links, add template path to complete relative urls
65
+ unless true #is_absolute?(href)
66
+ if href[/\A\//] # link begins with /
67
+ href = '?'
68
+ else
69
+ href = closest_directory(@headers[:template_path]) + href
70
+ end
71
+ link.set_attribute('href', href)
72
+ end
73
+
74
+ case href
75
+ when /\A#{proxy_base}/
76
+ href.sub!(/#{proxy_base}/,'').sub!(/\A\//,'')
77
+ when /\A#{URI.parse(proxy_base).path}/
78
+ href.sub!(/#{URI.parse(proxy_base).path}/,'').sub!(/\A\//,'')
79
+ end
80
+
81
+ unless is_absolute?(href)
82
+ href = closest_directory(@headers[:template_path]) + href
83
+ end
84
+
85
+ link.set_attribute('href', href)
86
+ end
87
+ end
88
+
89
+
90
+ def load_externals
91
+ (content/EXTERNAL_SEARCH_PATTERN).each do |element|
92
+ external = self.class.new(Matryoshka::External.find(element[:href]))
93
+ external.make_links_absolute(element[:href])
94
+ if external.status == 200
95
+ Merge.new(element,external.content,Merge::EXTERNAL_MERGE).run
96
+ # Cleanup external code
97
+ element.remove_attribute(:href)
98
+ element.remove_attribute(:rel)
99
+ end
100
+ end
101
+ @externals_loaded = true
102
+ end
103
+
104
+ def make_links_absolute(base_url, replace_pairs = {'a'=>'href', 'img'=>'src'})
105
+ base_dir = base_url[/\A.+\//]
106
+ replace_pairs.each_pair do |search_pattern, attribute|
107
+ (content/search_pattern).each do |link|
108
+ absolute_link link, attribute, base_dir
109
+ end
110
+ end
111
+ end
112
+
113
+ def is_absolute?(uri)
114
+ uri[/\Ahttp:\/\//]
115
+ end
116
+
117
+ def absolute_link(elem,attribute,base_dir)
118
+ relative_uri = elem.attributes[attribute]
119
+ unless (relative_uri.include?(base_dir) or is_absolute?(relative_uri))
120
+ elem.set_attribute(attribute, (base_dir + relative_uri))
121
+ end
122
+ end
123
+
124
+ def initialize(rack_array)
125
+ self.status = rack_array[0]
126
+ self.headers = rack_array[1]
127
+
128
+ html = rack_array[2]
129
+ if html.respond_to?(:to_html)
130
+ self.content = html
131
+ else
132
+ self.body = html
133
+ end
134
+ load_externals unless externals_loaded?
135
+ end
136
+
137
+ def content
138
+ @content ||= Hpricot(body)
139
+ end
140
+
141
+ def body
142
+ @content ? content.to_html : @body
143
+ end
144
+
145
+ def self.extentions
146
+ ['.html','.htm']
147
+ end
148
+
149
+ def self.accepts
150
+ ['text/html']
151
+ end
152
+
153
+ def status
154
+ @status or 200
155
+ end
156
+
157
+ # this needs to update headers like 'Content-Length' and remove Matryoshka-specific ones
158
+ # Might need to make this cleaned_headers or something
159
+ def headers
160
+ @headers.
161
+ reject {|k,v| k.is_a? Symbol}.
162
+ merge({"Content-Type" => "text/html",
163
+ 'Content-Length' => content.to_html.length.to_s})
164
+ end
165
+
166
+ def call(env)
167
+ # content = IO.read Matryoshka::ROOT_DIR + '/public/index.html'
168
+ [status, headers, body]
169
+ end
170
+
171
+ end
@@ -0,0 +1,201 @@
1
+ class Matryoshka::Document::Html::Merge
2
+ @@round = 0
3
+
4
+ DEFAULT_MERGE = [
5
+ {:empty=>:full},
6
+ {:doc=>:remerge_children},
7
+ {:id=>:replace},
8
+ {:before_id=>:before},
9
+ {:after_id=>:append},
10
+ {:default=>:end_of_tag}
11
+ ]
12
+
13
+ EXTERNAL_MERGE = [
14
+ {:original_id => :replace_id},
15
+ {:original_selector => :selector},
16
+ {:nochildren=>:inside_body},
17
+ {:doc => :remerge_original_children},
18
+ # {:id=>:replace},
19
+ # {:parent=>:insert}, # This translate to before_id or after_id
20
+ {:all=>:remerge_children}
21
+ ]
22
+
23
+ # original is the parent document
24
+ # additional is the document to be merged
25
+ # corresponding is the matching portion of the original doc
26
+ # methodologies are the techniques used to merge, in order
27
+ # [{matching_pattern => what_to_do_if_match}, ...]
28
+ attr_accessor :original, :additional, :corresponding, :methodologies
29
+
30
+ def initialize(orig,add, meth = DEFAULT_MERGE)
31
+ self.original = convert_to_parse_format(orig)
32
+ self.additional = convert_to_parse_format(add)
33
+ self.methodologies = meth
34
+ end
35
+
36
+ def run
37
+ # puts "Round #{@@round += 1}"
38
+ methodologies.each do |methodology|
39
+ methodology.each_pair do |find_method, merge_technique|
40
+ # puts "#{@@round} - Doing #{find_method}:#{merge_technique} on #{additional.to_html[0..50].gsub(/\n/,'')}"
41
+ # debugger if @@round < 2
42
+ if (mergeable? and corresponding_match(find_method))
43
+ send merge_technique
44
+ return original
45
+ end
46
+ end
47
+ end
48
+ # This wasn't in previous versions ... may be some reason to avoid.
49
+ return original
50
+ end
51
+
52
+ def corresponding_match(find_method)
53
+ self.corresponding = send(find_method)
54
+ end
55
+
56
+ def convert_to_parse_format(data)
57
+ if data.respond_to? :content # Html object
58
+ # This should already be in Hpricot
59
+ data.content
60
+ elsif data.respond_to? :to_html # Hpricot object
61
+ data
62
+ else # probably string or IO
63
+ Hpricot data
64
+ end
65
+ end
66
+
67
+ # Below are matchign and replacing methods
68
+ # Perhaps move them to a separate module later
69
+ def empty
70
+ original if original.inner_html.empty?
71
+ end
72
+
73
+ def full
74
+ corresponding.inner_html = additional.inner_html
75
+ end
76
+
77
+ def doc
78
+ # original unless additional.kind_of? Nokogiri::HTML::Element
79
+ original if additional.class == Hpricot::Doc
80
+ end
81
+
82
+ def remerge_children
83
+ additional.children.each do |elem|
84
+ # if elem.kind_of? Nokogiri::XML::Element
85
+ if elem.kind_of? Hpricot::Elem
86
+ self.class.new(corresponding,elem,methodologies).run
87
+ end
88
+ end
89
+
90
+ rescue
91
+ puts '*' * 75
92
+ puts "#{@@round} - Rescuing: #{additional.class} cannot be children'd"
93
+ puts "#{@@round} - #{additional}"
94
+ # debugger
95
+ end
96
+
97
+ def remerge_original_children
98
+ corresponding.children.each do |elem|
99
+ if elem.kind_of? Hpricot::Elem
100
+ self.class.new(elem, additional, methodologies).run
101
+ end
102
+ end
103
+ end
104
+
105
+ # Some external-specific merging methods
106
+ def original_id
107
+ original if additional.at("##{original.attributes['id']}") if original.attributes['id']
108
+ end
109
+
110
+ def replace_id
111
+ corresponding.swap additional.at("##{corresponding.attributes['id']}").to_html
112
+ end
113
+
114
+ def original_selector
115
+ if original.attributes['rel'] == 'selector'
116
+ original if additional.at(original.attributes['href'])
117
+ end
118
+ end
119
+
120
+ def selector
121
+ corresponding.swap additional.at(corresponding.attributes['href']).to_html
122
+ end
123
+
124
+ # End externa-specific merging methods
125
+
126
+ def id
127
+ original.at("##{additional.attributes['id']}") if additional.attributes['id']
128
+ end
129
+
130
+ def replace
131
+ corresponding.swap additional.to_html
132
+ end
133
+
134
+ ## These are quickly tacked on.
135
+
136
+ def additional_id
137
+ additional.attributes['id'] if additional.respond_to? :attributes
138
+ end
139
+
140
+ def before_id
141
+ if additional_id
142
+ if additional_id.index('before__') == 0
143
+ original.at("##{additional_id.sub('before__','')}")
144
+ end
145
+ end
146
+ end
147
+
148
+ def before
149
+ corresponding.before(additional.to_html)
150
+ end
151
+
152
+ def after_id
153
+ if additional_id
154
+ if additional_id.index('after__') == 0
155
+ original.at("##{additional_id.sub('after__','')}")
156
+ end
157
+ end
158
+ end
159
+
160
+ def append
161
+ corresponding.after(additional.to_html)
162
+ end
163
+
164
+ def default
165
+ original.at('body') or original
166
+ end
167
+
168
+ def end_of_tag
169
+ corresponding.inner_html = corresponding.inner_html + additional.to_html
170
+ end
171
+
172
+ def nochildren
173
+ # Fails on Hpricot::Docs
174
+ #
175
+ # if original.class == Hpricot::Doc
176
+ # return false
177
+ # end
178
+ original.children.each do |child|
179
+ if child.class == Hpricot::Elem
180
+ return false
181
+ end
182
+ end
183
+ original.at('*')
184
+ end
185
+
186
+ def inside_body
187
+ corresponding.inner_html = begin
188
+ additional.at('body') or additional
189
+ end.to_html
190
+ end
191
+
192
+ def all
193
+ original
194
+ end
195
+
196
+ def mergeable?
197
+ acceptable_classes_for_merging = [Hpricot::Elem, Hpricot::Doc]
198
+ acceptable_classes_for_merging.include? additional.class
199
+ end
200
+
201
+ end
@@ -0,0 +1,13 @@
1
+ class Matryoshka::Document::Unknown
2
+ def initialize(*args)
3
+ end
4
+
5
+ # These never match.
6
+ def self.extentions ; [] ; end
7
+ def self.accepts ; [] ;end
8
+
9
+ def call(env)
10
+ content = "Can't handle that kind of request."
11
+ [501, {"Content-Type" => "text/html", 'Content-Length' => content.length.to_s}, content]
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ require 'open-uri'
2
+
3
+ class Matryoshka::External
4
+ def self.find(uri,options = {})
5
+ [200,{}.merge(options),open(uri)]
6
+ rescue
7
+ [404,{}.merge(options),'<p>404 on external</p>']
8
+ end
9
+ end
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{matryoshka}
5
+ s.version = "0.0.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Sam Schenkman-Moore"]
9
+ s.date = %q{2009-11-04}
10
+ s.description = %q{Rack middleware for parsing html templates.}
11
+ s.email = %q{samsm@samsm.com}
12
+ s.extra_rdoc_files = ["lib/matryoshka.rb", "lib/matryoshka/answer.rb", "lib/matryoshka/data.rb", "lib/matryoshka/document.rb", "lib/matryoshka/document/delegate.rb", "lib/matryoshka/document/html.rb", "lib/matryoshka/document/html/merge.rb", "lib/matryoshka/document/unknown.rb", "lib/matryoshka/external.rb"]
13
+ s.files = ["Manifest", "Rakefile", "config.ru", "lib/matryoshka.rb", "lib/matryoshka/answer.rb", "lib/matryoshka/data.rb", "lib/matryoshka/document.rb", "lib/matryoshka/document/delegate.rb", "lib/matryoshka/document/html.rb", "lib/matryoshka/document/html/merge.rb", "lib/matryoshka/document/unknown.rb", "lib/matryoshka/external.rb", "public/README", "templates/image.jpg", "templates/index.html", "templates/proxy/index.html", "templates/test/about.html", "templates/test/index.html", "matryoshka.gemspec"]
14
+ s.homepage = %q{http://samsm.com/}
15
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Matryoshka"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = %q{matryoshka}
18
+ s.rubygems_version = %q{1.3.5}
19
+ s.summary = %q{Rack middleware for parsing html templates.}
20
+
21
+ if s.respond_to? :specification_version then
22
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
23
+ s.specification_version = 3
24
+
25
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
26
+ s.add_development_dependency(%q<hpricot>, [">= 0"])
27
+ else
28
+ s.add_dependency(%q<hpricot>, [">= 0"])
29
+ end
30
+ else
31
+ s.add_dependency(%q<hpricot>, [">= 0"])
32
+ end
33
+ end
@@ -0,0 +1,2 @@
1
+ File placed in this folder will be read directly by the upstream
2
+ server (Apache, etc) with no special Matryoshka processing.
Binary file
@@ -0,0 +1,15 @@
1
+ <html>
2
+ <head>
3
+ <title>Hi</title>
4
+ </head>
5
+ <body>
6
+ <div>
7
+ <img src="/image.jpg">
8
+ <a href="a.pdf">A link to a pdf</a>
9
+ </div>
10
+ <div id="test"></div>
11
+ <div id="content">
12
+ This is from /index.html
13
+ </div>
14
+ </body>
15
+ </html>
@@ -0,0 +1,3 @@
1
+ <div rel="proxy" href="http://tumble.samsm.com/">
2
+ <div id="container">Proxy div, unloaded, apparently.</div>
3
+ </div>
@@ -0,0 +1,12 @@
1
+ <div id="content">
2
+ This is from /test/about.html
3
+ </div>
4
+
5
+ <div id="test">
6
+ Test div! Should appear above the "this is from" message thanks to a second replace (shows that remerge children probably works).
7
+ </div>
8
+
9
+ <div id="before__test">This should come before the test div.</div>
10
+ <div id="after__test">This should come after the test div.</div>
11
+
12
+ <div>No matryoshka code, should be placed using a default rule.</div>
@@ -0,0 +1,8 @@
1
+ <div id="test">
2
+ This is from /test/index.html
3
+ </div>>
4
+
5
+ <div rel="external" href="http://samsm.com/">
6
+ <div id="test"></div>
7
+ <ul rel="selector" href="ul"></ul>
8
+ </div>
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: matryoshka
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Sam Schenkman-Moore
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-04 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hpricot
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description: Rack middleware for parsing html templates.
26
+ email: samsm@samsm.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - lib/matryoshka.rb
33
+ - lib/matryoshka/answer.rb
34
+ - lib/matryoshka/data.rb
35
+ - lib/matryoshka/document.rb
36
+ - lib/matryoshka/document/delegate.rb
37
+ - lib/matryoshka/document/html.rb
38
+ - lib/matryoshka/document/html/merge.rb
39
+ - lib/matryoshka/document/unknown.rb
40
+ - lib/matryoshka/external.rb
41
+ files:
42
+ - Manifest
43
+ - Rakefile
44
+ - config.ru
45
+ - lib/matryoshka.rb
46
+ - lib/matryoshka/answer.rb
47
+ - lib/matryoshka/data.rb
48
+ - lib/matryoshka/document.rb
49
+ - lib/matryoshka/document/delegate.rb
50
+ - lib/matryoshka/document/html.rb
51
+ - lib/matryoshka/document/html/merge.rb
52
+ - lib/matryoshka/document/unknown.rb
53
+ - lib/matryoshka/external.rb
54
+ - public/README
55
+ - templates/image.jpg
56
+ - templates/index.html
57
+ - templates/proxy/index.html
58
+ - templates/test/about.html
59
+ - templates/test/index.html
60
+ - matryoshka.gemspec
61
+ has_rdoc: true
62
+ homepage: http://samsm.com/
63
+ licenses: []
64
+
65
+ post_install_message:
66
+ rdoc_options:
67
+ - --line-numbers
68
+ - --inline-source
69
+ - --title
70
+ - Matryoshka
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: "0"
78
+ version:
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: "1.2"
84
+ version:
85
+ requirements: []
86
+
87
+ rubyforge_project: matryoshka
88
+ rubygems_version: 1.3.5
89
+ signing_key:
90
+ specification_version: 3
91
+ summary: Rack middleware for parsing html templates.
92
+ test_files: []
93
+