html_mockup 0.6.5 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +8 -0
- data/html_mockup.gemspec +1 -1
- data/lib/html_mockup/extractor.rb +31 -62
- data/lib/html_mockup/rack/html_mockup.rb +17 -22
- data/lib/html_mockup/release/scm/git.rb +2 -2
- data/lib/html_mockup/resolver.rb +95 -0
- data/lib/html_mockup/server.rb +1 -1
- data/lib/html_mockup/template.rb +18 -23
- metadata +11 -10
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## Version 0.7.0
|
4
|
+
* Replace --quiet with -s in as it's no longer supported in newer GIT versions
|
5
|
+
* Add support for ENV passing to the partials
|
6
|
+
* Add support for single file processing and env passing in the extractor (release)
|
7
|
+
* Refactor path and url resolving
|
8
|
+
* Allow `.html` files to be processed by ERB (both in release and serve)
|
9
|
+
* Pass "MOCKUP_PROJECT" variable to env (both in release and serve)
|
10
|
+
|
3
11
|
## Version 0.6.5
|
4
12
|
* Allow disabling of URL relativizing in the extractor with `release.extract :url_relativize => false`
|
5
13
|
* Add missing Hpricot dependency to gem
|
data/html_mockup.gemspec
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'hpricot'
|
2
|
+
require File.dirname(__FILE__) + '/resolver'
|
2
3
|
|
3
4
|
module HtmlMockup
|
4
5
|
class Extractor
|
@@ -12,21 +13,27 @@ module HtmlMockup
|
|
12
13
|
|
13
14
|
# @option options [Array] :url_attributes The element attributes to parse and relativize
|
14
15
|
# @option options [Array] :url_relativize Wether or not we should relativize
|
16
|
+
# @option options [Array] :env ENV variable to pass to template renderer.
|
15
17
|
def initialize(project, target_path, options={})
|
16
18
|
@project = project
|
17
19
|
@target_path = Pathname.new(target_path)
|
20
|
+
@resolver = Resolver.new(self.target_path)
|
21
|
+
|
18
22
|
|
19
23
|
@options = {
|
20
24
|
:url_attributes => %w{src href action},
|
21
|
-
:url_relativize => true
|
25
|
+
:url_relativize => true,
|
26
|
+
:env => {}
|
22
27
|
}
|
23
28
|
|
24
29
|
@options.update(options) if options
|
30
|
+
|
31
|
+
env.update("MOCKUP_PROJECT" => project)
|
25
32
|
end
|
26
33
|
|
27
34
|
def run!
|
28
35
|
target_path = self.target_path
|
29
|
-
source_path
|
36
|
+
source_path = self.project.html_path
|
30
37
|
|
31
38
|
|
32
39
|
filter = "**/*.html"
|
@@ -39,86 +46,48 @@ module HtmlMockup
|
|
39
46
|
cp_r(source_path.children, target_path)
|
40
47
|
|
41
48
|
Dir.chdir(source_path) do
|
42
|
-
Dir.glob(filter).each do |
|
43
|
-
|
44
|
-
|
45
|
-
if @options[:url_relativize]
|
46
|
-
source = relativize_urls(source, file_name)
|
47
|
-
end
|
48
|
-
|
49
|
-
File.open(target_path + file_name,"w"){|f| f.write(source) }
|
49
|
+
Dir.glob(filter).each do |file_path|
|
50
|
+
self.run_on_file!(file_path, @options[:env])
|
50
51
|
end
|
51
52
|
end
|
52
53
|
end
|
54
|
+
|
55
|
+
def run_on_file!(file_path, env = {})
|
56
|
+
source = self.extract_source_from_file(file_path, env)
|
57
|
+
File.open(target_path + file_path,"w"){|f| f.write(source) }
|
58
|
+
end
|
59
|
+
|
60
|
+
# Runs the extractor on a single file and return processed source.
|
61
|
+
def extract_source_from_file(file_path, env = {})
|
62
|
+
source = HtmlMockup::Template.open(file_path, :partial_path => self.project.partial_path).render(env)
|
63
|
+
|
64
|
+
if @options[:url_relativize]
|
65
|
+
source = relativize_urls(source, file_path)
|
66
|
+
end
|
53
67
|
|
68
|
+
source
|
69
|
+
end
|
70
|
+
|
54
71
|
|
55
72
|
protected
|
56
73
|
|
57
|
-
def relativize_urls(source,
|
58
|
-
cur_dir = Pathname.new(file_name).dirname
|
59
|
-
up_to_root = File.join([".."] * (file_name.split("/").size - 1))
|
60
|
-
|
74
|
+
def relativize_urls(source, file_path)
|
61
75
|
doc = Hpricot(source)
|
62
76
|
@options[:url_attributes].each do |attribute|
|
63
77
|
(doc/"*[@#{attribute}]").each do |tag|
|
64
|
-
converted_url =
|
78
|
+
converted_url = @resolver.url_to_relative_url(tag[attribute], file_path)
|
65
79
|
|
66
80
|
case converted_url
|
67
81
|
when String
|
68
82
|
tag[attribute] = converted_url
|
69
83
|
when nil
|
70
|
-
puts "Could not resolve link #{tag[attribute]} in #{
|
84
|
+
puts "Could not resolve link #{tag[attribute]} in #{file_path}"
|
71
85
|
end
|
72
86
|
end
|
73
87
|
end
|
74
88
|
|
75
89
|
doc.to_original_html
|
76
90
|
end
|
77
|
-
|
78
|
-
# @return [false, nil, String] False if it can't be converted, nil if it can't be resolved and the converted string if it can be resolved.
|
79
|
-
def convert_relative_url_to_absolute_url(url, cur_dir, up_to_root)
|
80
|
-
# Skip if the url doesn't start with a / (but not with //)
|
81
|
-
return false unless url =~ /\A\/[^\/]/
|
82
|
-
|
83
|
-
# Strip off anchors
|
84
|
-
anchor = nil
|
85
|
-
url.gsub!(/(#.+)\Z/) do |r|
|
86
|
-
anchor = r
|
87
|
-
""
|
88
|
-
end
|
89
|
-
|
90
|
-
# Strip off query strings
|
91
|
-
query = nil
|
92
|
-
url.gsub!(/(\?.+)\Z/) do |r|
|
93
|
-
query = r
|
94
|
-
""
|
95
|
-
end
|
96
|
-
|
97
|
-
if true_file = resolve_path(cur_dir + up_to_root + url.sub(/\A\//,""))
|
98
|
-
url = true_file.relative_path_from(cur_dir).to_s
|
99
|
-
url += query if query
|
100
|
-
url += anchor if anchor
|
101
|
-
url
|
102
|
-
else
|
103
|
-
nil
|
104
|
-
end
|
105
|
-
|
106
|
-
end
|
107
|
-
|
108
|
-
def resolve_path(path)
|
109
|
-
path = Pathname.new(path) unless path.kind_of?(Pathname)
|
110
|
-
# Append index.html/index.htm/index.rhtml if it's a diretory
|
111
|
-
if path.directory?
|
112
|
-
search_files = %w{.html .htm}.map!{|p| path + "index#{p}" }
|
113
|
-
# If it ends with a slash or does not contain a . and it's not a directory
|
114
|
-
# try to add .html/.htm to see if that exists.
|
115
|
-
elsif (path.to_s =~ /\/$/) || (path.to_s =~ /^[^.]+$/)
|
116
|
-
search_files = [path.to_s + ".html", path.to_s + ".htm"].map!{|p| Pathname.new(p) }
|
117
|
-
else
|
118
|
-
search_files = [path]
|
119
|
-
end
|
120
|
-
search_files.find{|p| p.exist? }
|
121
|
-
end
|
122
|
-
|
91
|
+
|
123
92
|
end
|
124
93
|
end
|
@@ -2,42 +2,37 @@ require 'rack/request'
|
|
2
2
|
require 'rack/response'
|
3
3
|
require 'rack/file'
|
4
4
|
|
5
|
+
require File.dirname(__FILE__) + '/../resolver'
|
6
|
+
|
5
7
|
module HtmlMockup
|
6
8
|
module Rack
|
9
|
+
|
7
10
|
class HtmlMockup
|
8
|
-
|
11
|
+
|
12
|
+
attr_reader :project
|
13
|
+
|
14
|
+
def initialize(project)
|
15
|
+
@project = project
|
16
|
+
root,partial_path = project.html_path, project.partial_path
|
17
|
+
|
9
18
|
@docroot = root
|
10
19
|
@partial_path = partial_path
|
11
20
|
@file_server = ::Rack::File.new(@docroot)
|
12
21
|
end
|
13
22
|
|
14
23
|
def call(env)
|
15
|
-
|
16
|
-
|
17
|
-
# TODO: Combine with Extractor#resolve_path
|
24
|
+
url = env["PATH_INFO"]
|
25
|
+
env["MOCKUP_PROJECT"] = project
|
18
26
|
|
19
|
-
|
20
|
-
if File.directory?(File.join(@docroot,path))
|
21
|
-
search_files = %w{.html .htm}.map!{|p| File.join(@docroot,path,"index#{p}")}
|
22
|
-
# If it's already a .html/.htm file, render that file
|
23
|
-
elsif (path =~ /\.html?$/)
|
24
|
-
search_files = [File.join(@docroot,path)]
|
25
|
-
# If it ends with a slash or does not contain a . and it's not a directory
|
26
|
-
# try to add .html/.htm to see if that exists.
|
27
|
-
elsif (path =~ /\/$/) || (path =~ /^[^.]+$/)
|
28
|
-
search_files = [path + ".html", path + ".htm"].map!{|p| File.join(@docroot,p) }
|
29
|
-
# Otherwise don't render anything at all.
|
30
|
-
else
|
31
|
-
search_files = []
|
32
|
-
end
|
27
|
+
resolver = Resolver.new(@docroot)
|
33
28
|
|
34
|
-
if template_path =
|
35
|
-
env["rack.errors"].puts "Rendering template #{template_path.inspect} (#{
|
29
|
+
if template_path = resolver.url_to_path(url)
|
30
|
+
env["rack.errors"].puts "Rendering template #{template_path.inspect} (#{url.inspect})"
|
36
31
|
begin
|
37
32
|
templ = ::HtmlMockup::Template.open(template_path, :partial_path => @partial_path)
|
38
33
|
resp = ::Rack::Response.new do |res|
|
39
34
|
res.status = 200
|
40
|
-
res.write templ.render
|
35
|
+
res.write templ.render(env)
|
41
36
|
end
|
42
37
|
resp.finish
|
43
38
|
rescue StandardError => e
|
@@ -49,7 +44,7 @@ module HtmlMockup
|
|
49
44
|
resp.finish
|
50
45
|
end
|
51
46
|
else
|
52
|
-
env["rack.errors"].puts "Invoking file handler for #{
|
47
|
+
env["rack.errors"].puts "Invoking file handler for #{url.inspect}"
|
53
48
|
@file_server.call(env)
|
54
49
|
end
|
55
50
|
end
|
@@ -61,7 +61,7 @@ module HtmlMockup::Release::Scm
|
|
61
61
|
|
62
62
|
if $?.to_i > 0
|
63
63
|
# HEAD is not a tagged verison, get the short SHA1 instead
|
64
|
-
@_version = `git --git-dir=#{git_dir} show #{ref} --format=format:"%h"
|
64
|
+
@_version = `git --git-dir=#{git_dir} show #{ref} --format=format:"%h" -s 2>&1`
|
65
65
|
else
|
66
66
|
# HEAD is a tagged version, if version is prefixed with "v" it will be stripped off
|
67
67
|
@_version.gsub!(/^v/,"")
|
@@ -69,7 +69,7 @@ module HtmlMockup::Release::Scm
|
|
69
69
|
@_version.strip!
|
70
70
|
|
71
71
|
# Get the date in epoch time
|
72
|
-
date = `git --git-dir=#{git_dir} show #{ref} --format=format:"%ct"
|
72
|
+
date = `git --git-dir=#{git_dir} show #{ref} --format=format:"%ct" -s 2>&1`
|
73
73
|
if date =~ /\d+/
|
74
74
|
@_date = Time.at(date.to_i)
|
75
75
|
else
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module HtmlMockup
|
2
|
+
class Resolver
|
3
|
+
|
4
|
+
def initialize(path)
|
5
|
+
@base = Pathname.new(path)
|
6
|
+
end
|
7
|
+
|
8
|
+
def url_to_path(url, exact_match = false)
|
9
|
+
path, qs, anch = strip_query_string_and_anchor(url.to_s)
|
10
|
+
|
11
|
+
extensions = %w{html htm}
|
12
|
+
|
13
|
+
# Append index.extension if it's a diretory
|
14
|
+
if File.directory?(File.join(@base,path))
|
15
|
+
search_files = extensions.map{|p| File.join(@base,path,"index.#{p}")}
|
16
|
+
# If it's already a .extension file, return that file
|
17
|
+
elsif extensions.detect{|e| path =~ /\.#{e}\Z/ }
|
18
|
+
search_files = [File.join(@base,path)]
|
19
|
+
# If it ends with a slash or does not contain a . and it's not a directory
|
20
|
+
# try to add extenstions to see if that exists.
|
21
|
+
elsif (path =~ /\/$/) || (path =~ /^[^.]+$/)
|
22
|
+
search_files = extensions.map{|e| File.join(@base,"#{path}.#{e}") }
|
23
|
+
# Otherwise don't return anything at all.
|
24
|
+
else
|
25
|
+
if exact_match
|
26
|
+
search_files = [File.join(@base,path)]
|
27
|
+
else
|
28
|
+
search_files = []
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
if file = search_files.find{|p| File.exist?(p) }
|
33
|
+
Pathname.new(file)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
# Convert a disk path on file to an url
|
39
|
+
def path_to_url(path, relative_to = nil)
|
40
|
+
|
41
|
+
path = Pathname.new(path).relative_path_from(@base).cleanpath
|
42
|
+
|
43
|
+
if relative_to
|
44
|
+
if relative_to.to_s =~ /\A\//
|
45
|
+
relative_to = Pathname.new(File.dirname(relative_to.to_s)).relative_path_from(@base).cleanpath
|
46
|
+
else
|
47
|
+
relative_to = Pathname.new(File.dirname(relative_to.to_s))
|
48
|
+
end
|
49
|
+
path = Pathname.new("/" + path.to_s).relative_path_from(Pathname.new("/" + relative_to.to_s))
|
50
|
+
path.to_s
|
51
|
+
else
|
52
|
+
"/" + path.to_s
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
def url_to_relative_url(url, relative_to_path)
|
58
|
+
# Skip if the url doesn't start with a / (but not with //)
|
59
|
+
return false unless url =~ /\A\/[^\/]/
|
60
|
+
|
61
|
+
path, qs, anch = strip_query_string_and_anchor(url)
|
62
|
+
|
63
|
+
# Get disk path
|
64
|
+
if true_path = self.url_to_path(path, true)
|
65
|
+
path = self.path_to_url(true_path, relative_to_path)
|
66
|
+
path += qs if qs
|
67
|
+
path += anch if anch
|
68
|
+
path
|
69
|
+
else
|
70
|
+
false
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def strip_query_string_and_anchor(url)
|
75
|
+
url = url.dup
|
76
|
+
|
77
|
+
# Strip off anchors
|
78
|
+
anchor = nil
|
79
|
+
url.gsub!(/(#.+)\Z/) do |r|
|
80
|
+
anchor = r
|
81
|
+
""
|
82
|
+
end
|
83
|
+
|
84
|
+
# Strip off query strings
|
85
|
+
query = nil
|
86
|
+
url.gsub!(/(\?.+)\Z/) do |r|
|
87
|
+
query = r
|
88
|
+
""
|
89
|
+
end
|
90
|
+
|
91
|
+
[url, query, anchor]
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
data/lib/html_mockup/server.rb
CHANGED
@@ -65,7 +65,7 @@ module HtmlMockup
|
|
65
65
|
return @app if @app
|
66
66
|
|
67
67
|
@stack.use Rack::HtmlValidator if self.options[:validate]
|
68
|
-
@stack.run Rack::HtmlMockup.new(self.project
|
68
|
+
@stack.run Rack::HtmlMockup.new(self.project)
|
69
69
|
|
70
70
|
@app = @stack
|
71
71
|
end
|
data/lib/html_mockup/template.rb
CHANGED
@@ -2,6 +2,7 @@ require 'pathname'
|
|
2
2
|
require 'strscan'
|
3
3
|
require 'erb'
|
4
4
|
require 'cgi'
|
5
|
+
require 'tilt'
|
5
6
|
|
6
7
|
module HtmlMockup
|
7
8
|
|
@@ -10,7 +11,7 @@ module HtmlMockup
|
|
10
11
|
class Template
|
11
12
|
|
12
13
|
class << self
|
13
|
-
def open(filename,options={})
|
14
|
+
def open(filename, options={})
|
14
15
|
raise "Unknown file #{filename}" unless File.exist?(filename)
|
15
16
|
self.new(File.read(filename),options.update(:target_file => filename))
|
16
17
|
end
|
@@ -39,18 +40,17 @@ module HtmlMockup
|
|
39
40
|
|
40
41
|
# Create a new HtmlMockupTemplate
|
41
42
|
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
# options<Hash>:: See options
|
43
|
+
# @param [String] source The template to parse
|
44
|
+
# @param [Hash] options See options
|
45
45
|
#
|
46
|
-
#
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
@
|
46
|
+
# @option options [String] partial_path Path where the partials reside (default: $0/../../partials)
|
47
|
+
def initialize(source, options={})
|
48
|
+
defaults = {
|
49
|
+
:partial_path => File.dirname(__FILE__) + "/../../partials/"
|
50
|
+
}
|
51
|
+
@source = source
|
52
|
+
@template = Tilt::ERBTemplate.new{ @source }
|
52
53
|
@options = defaults.update(options)
|
53
|
-
@scanner = StringScanner.new(@template)
|
54
54
|
raise "Partial path '#{self.options[:partial_path]}' not found" unless File.exist?(self.options[:partial_path])
|
55
55
|
end
|
56
56
|
|
@@ -65,6 +65,7 @@ module HtmlMockup
|
|
65
65
|
# String:: The rendered template
|
66
66
|
#--
|
67
67
|
def render(env={})
|
68
|
+
@scanner = StringScanner.new(@template.render(Object.new, :env => env))
|
68
69
|
out = ""
|
69
70
|
while (partial = self.parse_partial_tag!) do
|
70
71
|
tag,params,scanned = partial
|
@@ -73,7 +74,7 @@ module HtmlMockup
|
|
73
74
|
|
74
75
|
# scan until end of tag
|
75
76
|
current_content = self.scanner.scan_until(/<!-- \[STOP:#{tag}\] -->/)
|
76
|
-
out << (render_partial(tag, params) || current_content)
|
77
|
+
out << (render_partial(tag, params, env) || current_content)
|
77
78
|
end
|
78
79
|
out << scanner.rest
|
79
80
|
end
|
@@ -115,24 +116,18 @@ module HtmlMockup
|
|
115
116
|
unless self.available_partials[tag]
|
116
117
|
raise MissingPartial.new("Could not find partial '#{tag}' in partial path '#{@options[:partial_path]}'")
|
117
118
|
end
|
118
|
-
template =
|
119
|
-
context = TemplateContext.new(params
|
120
|
-
"\n" + template.
|
119
|
+
template = Tilt::ERBTemplate.new{ self.available_partials[tag] }
|
120
|
+
context = TemplateContext.new(params)
|
121
|
+
"\n" + template.render(context, :env => env).rstrip + "\n<!-- [STOP:#{tag}] -->"
|
121
122
|
end
|
122
123
|
|
123
124
|
class TemplateContext
|
124
125
|
# Params will be set as instance variables
|
125
|
-
def initialize(params
|
126
|
+
def initialize(params)
|
126
127
|
params.each do |k,v|
|
127
128
|
self.instance_variable_set("@#{k}",v)
|
128
129
|
end
|
129
|
-
|
130
|
-
@_env = env;
|
131
|
-
end
|
132
|
-
|
133
|
-
def env; @_env; end
|
134
|
-
|
135
|
-
def get_binding; binding(); end
|
130
|
+
end
|
136
131
|
end
|
137
132
|
|
138
133
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: html_mockup
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2013-01-22 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: thor
|
17
|
-
requirement: &
|
17
|
+
requirement: &70345877984660 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ~>
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: 0.16.0
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *70345877984660
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: rack
|
28
|
-
requirement: &
|
28
|
+
requirement: &70345877984180 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: 1.0.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *70345877984180
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: tilt
|
39
|
-
requirement: &
|
39
|
+
requirement: &70345877983700 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ! '>='
|
@@ -44,10 +44,10 @@ dependencies:
|
|
44
44
|
version: '0'
|
45
45
|
type: :runtime
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *70345877983700
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: hpricot
|
50
|
-
requirement: &
|
50
|
+
requirement: &70345877983200 !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
52
52
|
requirements:
|
53
53
|
- - ! '>='
|
@@ -55,7 +55,7 @@ dependencies:
|
|
55
55
|
version: 0.6.4
|
56
56
|
type: :runtime
|
57
57
|
prerelease: false
|
58
|
-
version_requirements: *
|
58
|
+
version_requirements: *70345877983200
|
59
59
|
description:
|
60
60
|
email:
|
61
61
|
- info@digitpaint.nl
|
@@ -101,6 +101,7 @@ files:
|
|
101
101
|
- lib/html_mockup/release/processors/yuicompressor.rb
|
102
102
|
- lib/html_mockup/release/scm.rb
|
103
103
|
- lib/html_mockup/release/scm/git.rb
|
104
|
+
- lib/html_mockup/resolver.rb
|
104
105
|
- lib/html_mockup/server.rb
|
105
106
|
- lib/html_mockup/template.rb
|
106
107
|
- lib/html_mockup/w3c_validator.rb
|