html_mockup 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/mockup +0 -0
- data/lib/html_mockup/cli.rb +38 -85
- data/lib/html_mockup/extractor.rb +100 -0
- data/lib/html_mockup/mockupfile.rb +63 -0
- data/lib/html_mockup/project.rb +54 -0
- data/lib/html_mockup/rack/html_mockup.rb +8 -6
- data/lib/html_mockup/rack/sleep.rb +21 -0
- data/lib/html_mockup/release/finalizers/dir.rb +24 -0
- data/lib/html_mockup/release/finalizers/zip.rb +4 -0
- data/lib/html_mockup/release/finalizers.rb +11 -0
- data/lib/html_mockup/release/injector.rb +98 -0
- data/lib/html_mockup/release/processors/requirejs.rb +54 -0
- data/lib/html_mockup/release/processors/sass.rb +38 -0
- data/lib/html_mockup/release/processors/yuicompressor.rb +53 -0
- data/lib/html_mockup/release/processors.rb +11 -0
- data/lib/html_mockup/release/scm/git.rb +101 -0
- data/lib/html_mockup/release/scm.rb +32 -0
- data/lib/html_mockup/release.rb +312 -0
- data/lib/html_mockup/server.rb +30 -10
- metadata +36 -8
data/bin/mockup
CHANGED
File without changes
|
data/lib/html_mockup/cli.rb
CHANGED
@@ -6,29 +6,32 @@ require 'fileutils'
|
|
6
6
|
include FileUtils
|
7
7
|
|
8
8
|
require File.dirname(__FILE__) + "/template"
|
9
|
+
require File.dirname(__FILE__) + "/project"
|
9
10
|
require File.dirname(__FILE__) + "/w3c_validator"
|
10
11
|
|
11
12
|
module HtmlMockup
|
12
13
|
class Cli < Thor
|
13
14
|
desc "serve [directory]","Serve directory as HTML, defaults to current directory"
|
14
15
|
method_options :port => :string, # Defaults to 9000
|
15
|
-
:
|
16
|
-
:
|
16
|
+
:html_path => :string, # The document root, defaults to "[directory]/html"
|
17
|
+
:partial_path => :string, # Defaults to [directory]/partials
|
17
18
|
:handler => :string # The handler to use (defaults to mongrel)
|
18
|
-
def serve(path=".")
|
19
|
-
|
19
|
+
def serve(path=".")
|
20
|
+
# Load the project, it should take care of all the paths
|
21
|
+
@project = initialize_project(path, options)
|
20
22
|
|
21
|
-
|
23
|
+
server = @project.server
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
server = Server.new(@path,@partial_path,options,server_options)
|
27
|
-
|
28
|
-
puts "Running HtmlMockup with #{server.handler.inspect} on port #{server_options[:Port]}"
|
29
|
-
puts " Taking partials from #{@partial_path} (#{HtmlMockup::Template.partial_files(@partial_path).size} found)"
|
25
|
+
puts "Running HtmlMockup with #{server.handler.inspect} on port #{server.port}"
|
26
|
+
puts banner(@project)
|
30
27
|
|
31
|
-
server.run
|
28
|
+
server.run!
|
29
|
+
end
|
30
|
+
|
31
|
+
desc "release [directory]", "Create a release for the project"
|
32
|
+
def release(path=".")
|
33
|
+
project = initialize_project(path, options)
|
34
|
+
project.release.run!
|
32
35
|
end
|
33
36
|
|
34
37
|
desc "validate [directory/file]", "Validates the file or all HTML in directory"
|
@@ -84,72 +87,35 @@ module HtmlMockup
|
|
84
87
|
end
|
85
88
|
end
|
86
89
|
|
87
|
-
desc "convert [directory]","Inject all partials, into all HTML files within directory"
|
88
|
-
method_options :partial_path => :string, # Defaults to [directory]/../partials
|
89
|
-
:filter => :string # What files should be converted defaults to **/*.html
|
90
|
-
def convert(path=".")
|
91
|
-
path,partial_path = template_paths(path,options["partial_path"])
|
92
|
-
filter = options["filter"] || "**/*.html"
|
93
|
-
puts "Converting #{filter} in #{path}"
|
94
|
-
puts " Taking partials from #{partial_path} (#{HtmlMockup::Template.partial_files(partial_path).size} found)"
|
95
|
-
|
96
|
-
if path.directory?
|
97
|
-
Dir.glob("#{path}/#{filter}").each do |file|
|
98
|
-
puts " Converting file: " + file
|
99
|
-
HtmlMockup::Template.open(file, :partial_path => partial_path).save
|
100
|
-
end
|
101
|
-
else
|
102
|
-
HtmlMockup::Template.open(path, :partial_path => partial_path).save
|
103
|
-
end
|
104
|
-
|
105
|
-
end
|
106
|
-
|
107
90
|
desc "extract [source_path] [target_path]", "Extract a fully relative html mockup into target_path. It will expand all absolute href's, src's and action's into relative links if they are absolute"
|
108
|
-
method_options :partial_path => :string, # Defaults to [directory]
|
91
|
+
method_options :partial_path => :string, # Defaults to [directory]/partials
|
109
92
|
:filter => :string # What files should be converted defaults to **/*.html
|
110
|
-
def extract(source_path=".",target_path="../out")
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
mkdir_p(target_path)
|
118
|
-
target_path = target_path.realpath
|
119
|
-
|
120
|
-
# Copy source to target first, we'll overwrite the templates later on.
|
121
|
-
cp_r(source_path.children,target_path)
|
122
|
-
|
123
|
-
Dir.chdir(source_path) do
|
124
|
-
Dir.glob(filter).each do |file_name|
|
125
|
-
source = HtmlMockup::Template.open(file_name, :partial_path => partial_path).render
|
126
|
-
cur_dir = Pathname.new(file_name).dirname
|
127
|
-
up_to_root = File.join([".."] * (file_name.split("/").size - 1))
|
128
|
-
doc = Hpricot(source)
|
129
|
-
%w{src href action}.each do |attribute|
|
130
|
-
(doc/"*[@#{attribute}]").each do |tag|
|
131
|
-
next unless tag[attribute] =~ /\A\//
|
132
|
-
if true_file = resolve_path(cur_dir + up_to_root + tag[attribute].sub(/\A\//,""))
|
133
|
-
tag[attribute] = true_file.relative_path_from(cur_dir).to_s
|
134
|
-
else
|
135
|
-
puts "Could not resolve link #{tag[attribute]} in #{file_name}"
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
File.open(target_path + file_name,"w"){|f| f.write(doc.to_original_html) }
|
141
|
-
end
|
142
|
-
end
|
93
|
+
def extract(source_path=".", target_path="../out")
|
94
|
+
project = initialize_project(source_path)
|
95
|
+
extractor = HtmlMockup::Extractor.new(project, target_path)
|
96
|
+
puts "Extracting mockup"
|
97
|
+
puts banner(project)
|
98
|
+
extractor.run!
|
143
99
|
end
|
144
100
|
|
145
101
|
protected
|
146
102
|
|
147
|
-
def
|
148
|
-
|
149
|
-
|
150
|
-
[path,partial_path]
|
103
|
+
def banner(project)
|
104
|
+
puts " Html: \"#{project.html_path}\""
|
105
|
+
puts " Partials: \"#{project.partial_path}\" (#{HtmlMockup::Template.partial_files(project.partial_path).size} found)"
|
151
106
|
end
|
152
107
|
|
108
|
+
# TODO: handle options
|
109
|
+
def initialize_project(path, options={})
|
110
|
+
|
111
|
+
if((Pathname.new(path) + "../partials").exist?)
|
112
|
+
puts "[ERROR]: Don't use the \"html\" path, use the project base path instead"
|
113
|
+
exit(1)
|
114
|
+
end
|
115
|
+
|
116
|
+
Project.new(path)
|
117
|
+
end
|
118
|
+
|
153
119
|
def w3cvalidate(file)
|
154
120
|
validator = W3CValidator.new(File.read(file))
|
155
121
|
validator.validate!
|
@@ -160,19 +126,6 @@ module HtmlMockup
|
|
160
126
|
validator.valid
|
161
127
|
end
|
162
128
|
|
163
|
-
|
164
|
-
path = Pathname.new(path) unless path.kind_of?(Pathname)
|
165
|
-
# Append index.html/index.htm/index.rhtml if it's a diretory
|
166
|
-
if path.directory?
|
167
|
-
search_files = %w{.html .htm}.map!{|p| path + "index#{p}" }
|
168
|
-
# If it ends with a slash or does not contain a . and it's not a directory
|
169
|
-
# try to add .html/.htm/.rhtml to see if that exists.
|
170
|
-
elsif (path.to_s =~ /\/$/) || (path.to_s =~ /^[^.]+$/)
|
171
|
-
search_files = [path.to_s + ".html", path.to_s + ".htm"].map!{|p| Pathname.new(p) }
|
172
|
-
else
|
173
|
-
search_files = [path]
|
174
|
-
end
|
175
|
-
search_files.find{|p| p.exist? }
|
176
|
-
end
|
129
|
+
|
177
130
|
end
|
178
131
|
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'hpricot'
|
2
|
+
|
3
|
+
module HtmlMockup
|
4
|
+
class Extractor
|
5
|
+
|
6
|
+
attr_reader :project, :target_path
|
7
|
+
|
8
|
+
def initialize(project, target_path)
|
9
|
+
@project = project
|
10
|
+
@target_path = Pathname.new(target_path)
|
11
|
+
end
|
12
|
+
|
13
|
+
def run!
|
14
|
+
target_path = self.target_path
|
15
|
+
source_path, partial_path = self.project.html_path, self.project.partial_path
|
16
|
+
|
17
|
+
|
18
|
+
filter = "**/*.html"
|
19
|
+
raise ArgumentError, "Target #{target_path} already exists, please choose a new directory to extract into" if target_path.exist?
|
20
|
+
|
21
|
+
mkdir_p(target_path)
|
22
|
+
target_path = target_path.realpath
|
23
|
+
|
24
|
+
# Copy source to target first, we'll overwrite the templates later on.
|
25
|
+
cp_r(source_path.children, target_path)
|
26
|
+
|
27
|
+
Dir.chdir(source_path) do
|
28
|
+
Dir.glob(filter).each do |file_name|
|
29
|
+
source = HtmlMockup::Template.open(file_name, :partial_path => partial_path).render
|
30
|
+
cur_dir = Pathname.new(file_name).dirname
|
31
|
+
up_to_root = File.join([".."] * (file_name.split("/").size - 1))
|
32
|
+
doc = Hpricot(source)
|
33
|
+
%w{src href action}.each do |attribute|
|
34
|
+
(doc/"*[@#{attribute}]").each do |tag|
|
35
|
+
converted_url = convert_relative_url_to_absolute_url(tag[attribute], cur_dir, up_to_root)
|
36
|
+
|
37
|
+
case converted_url
|
38
|
+
when String
|
39
|
+
tag[attribute] = converted_url
|
40
|
+
when nil
|
41
|
+
puts "Could not resolve link #{tag[attribute]} in #{file_name}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
File.open(target_path + file_name,"w"){|f| f.write(doc.to_original_html) }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
protected
|
53
|
+
|
54
|
+
# @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.
|
55
|
+
def convert_relative_url_to_absolute_url(url, cur_dir, up_to_root)
|
56
|
+
# Skip if the url doesn't start with a / (but not with //)
|
57
|
+
return false unless url =~ /\A\/[^\/]/
|
58
|
+
|
59
|
+
# Strip off anchors
|
60
|
+
anchor = nil
|
61
|
+
url.gsub!(/(#.+)\Z/) do |r|
|
62
|
+
anchor = r
|
63
|
+
""
|
64
|
+
end
|
65
|
+
|
66
|
+
# Strip off query strings
|
67
|
+
query = nil
|
68
|
+
url.gsub!(/(\?.+)\Z/) do |r|
|
69
|
+
query = r
|
70
|
+
""
|
71
|
+
end
|
72
|
+
|
73
|
+
if true_file = resolve_path(cur_dir + up_to_root + url.sub(/\A\//,""))
|
74
|
+
url = true_file.relative_path_from(cur_dir).to_s
|
75
|
+
url += query if query
|
76
|
+
url += anchor if anchor
|
77
|
+
url
|
78
|
+
else
|
79
|
+
nil
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
def resolve_path(path)
|
85
|
+
path = Pathname.new(path) unless path.kind_of?(Pathname)
|
86
|
+
# Append index.html/index.htm/index.rhtml if it's a diretory
|
87
|
+
if path.directory?
|
88
|
+
search_files = %w{.html .htm}.map!{|p| path + "index#{p}" }
|
89
|
+
# If it ends with a slash or does not contain a . and it's not a directory
|
90
|
+
# try to add .html/.htm to see if that exists.
|
91
|
+
elsif (path.to_s =~ /\/$/) || (path.to_s =~ /^[^.]+$/)
|
92
|
+
search_files = [path.to_s + ".html", path.to_s + ".htm"].map!{|p| Pathname.new(p) }
|
93
|
+
else
|
94
|
+
search_files = [path]
|
95
|
+
end
|
96
|
+
search_files.find{|p| p.exist? }
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module HtmlMockup
|
2
|
+
# Loader for mockupfile
|
3
|
+
class Mockupfile
|
4
|
+
|
5
|
+
# This is the context for the mockupfile evaluation. It should be empty except for the
|
6
|
+
# #mockup method.
|
7
|
+
class Context
|
8
|
+
|
9
|
+
def initialize(mockupfile)
|
10
|
+
@_mockupfile = mockupfile
|
11
|
+
end
|
12
|
+
|
13
|
+
def mockup
|
14
|
+
@_mockupfile
|
15
|
+
end
|
16
|
+
|
17
|
+
def binding
|
18
|
+
::Kernel.binding
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
# @attr :path [Pathname] The path of the Mockupfile for this project
|
24
|
+
attr_accessor :path, :project
|
25
|
+
|
26
|
+
def initialize(project)
|
27
|
+
@project = project
|
28
|
+
@path = Pathname.new(project.path + "Mockupfile")
|
29
|
+
end
|
30
|
+
|
31
|
+
# Actually load the mockupfile
|
32
|
+
def load
|
33
|
+
if File.exist?(@path) && !self.loaded?
|
34
|
+
@source = File.read(@path)
|
35
|
+
context = Context.new(self)
|
36
|
+
eval @source, context.binding
|
37
|
+
@loaded = true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Wether or not the Mockupfile has been loaded
|
42
|
+
def loaded?
|
43
|
+
@loaded
|
44
|
+
end
|
45
|
+
|
46
|
+
def release
|
47
|
+
if block_given?
|
48
|
+
yield(self.project.release)
|
49
|
+
end
|
50
|
+
self.project.release
|
51
|
+
end
|
52
|
+
|
53
|
+
def serve
|
54
|
+
if block_given?
|
55
|
+
yield(self.project.server)
|
56
|
+
end
|
57
|
+
self.project.server
|
58
|
+
end
|
59
|
+
|
60
|
+
alias :server :serve
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/release"
|
2
|
+
require File.dirname(__FILE__) + "/server"
|
3
|
+
require File.dirname(__FILE__) + "/mockupfile"
|
4
|
+
|
5
|
+
module HtmlMockup
|
6
|
+
# Loader for mockupfile
|
7
|
+
class Project
|
8
|
+
|
9
|
+
# @attr :path [Pathname] The project path
|
10
|
+
# @attr :html_path [Pathname] The path of the HTML mockup
|
11
|
+
# @attr :partial_path [Pathname] The path for the partials for this mockup
|
12
|
+
# @attr :mockupfile [Mockupfile] The Mockupfile for this project
|
13
|
+
attr_accessor :path, :html_path, :partial_path, :mockupfile
|
14
|
+
|
15
|
+
def initialize(path, options={})
|
16
|
+
@path = Pathname.new(path)
|
17
|
+
|
18
|
+
options = {
|
19
|
+
:html_path => @path + "html",
|
20
|
+
:partial_path => @path + "partials"
|
21
|
+
}.update(options)
|
22
|
+
|
23
|
+
html_path, partial_path = mockup_paths(options[:html_path], options[:partial_path])
|
24
|
+
@mockupfile = Mockupfile.new(self)
|
25
|
+
@mockupfile.load
|
26
|
+
end
|
27
|
+
|
28
|
+
def server
|
29
|
+
@server ||= Server.new(self.html_path, self.partial_path)
|
30
|
+
end
|
31
|
+
|
32
|
+
def release
|
33
|
+
@release ||= Release.new(self)
|
34
|
+
end
|
35
|
+
|
36
|
+
def html_path=(p)
|
37
|
+
@html_path = Pathname.new(p).realpath
|
38
|
+
end
|
39
|
+
|
40
|
+
def partial_path=(p)
|
41
|
+
@partial_path = Pathname.new(p).realpath
|
42
|
+
end
|
43
|
+
|
44
|
+
protected
|
45
|
+
|
46
|
+
def mockup_paths(html_path, partial_path = nil)
|
47
|
+
html_path = Pathname.new(html_path)
|
48
|
+
partial_path = partial_path && Pathname.new(partial_path) || (html_path + "../partials/")
|
49
|
+
[html_path, partial_path]
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -14,16 +14,18 @@ module HtmlMockup
|
|
14
14
|
def call(env)
|
15
15
|
path = env["PATH_INFO"]
|
16
16
|
|
17
|
-
#
|
17
|
+
# TODO: Combine with Extractor#resolve_path
|
18
|
+
|
19
|
+
# Append index.html/index.htm if it's a diretory
|
18
20
|
if File.directory?(File.join(@docroot,path))
|
19
|
-
search_files = %w{.html .htm
|
20
|
-
# If it's already a .html/.htm
|
21
|
-
elsif (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?$/)
|
22
24
|
search_files = [File.join(@docroot,path)]
|
23
25
|
# If it ends with a slash or does not contain a . and it's not a directory
|
24
|
-
# try to add .html/.htm
|
26
|
+
# try to add .html/.htm to see if that exists.
|
25
27
|
elsif (path =~ /\/$/) || (path =~ /^[^.]+$/)
|
26
|
-
search_files = [path + ".html", path + ".htm"
|
28
|
+
search_files = [path + ".html", path + ".htm"].map!{|p| File.join(@docroot,p) }
|
27
29
|
# Otherwise don't render anything at all.
|
28
30
|
else
|
29
31
|
search_files = []
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module HtmlMockup
|
2
|
+
module Rack
|
3
|
+
# Listens to the "sleep" parameter and sleeps the amount of seconds specified by the parameter. There is however a maximum of 5 seconds.
|
4
|
+
class Sleep
|
5
|
+
|
6
|
+
def initialize(app)
|
7
|
+
@app = app
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
r = Rack::Request.new(env)
|
12
|
+
if r.params["sleep"]
|
13
|
+
sleeptime = [r.params["sleep"].to_i, 5].min
|
14
|
+
sleep sleeptime
|
15
|
+
end
|
16
|
+
@app.call(env)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
# Finalizes the release into a directory in target_path
|
4
|
+
#
|
5
|
+
# The directory name will have the format PREFIX-VERSION
|
6
|
+
#
|
7
|
+
module HtmlMockup::Release::Finalizers
|
8
|
+
class Dir < Base
|
9
|
+
|
10
|
+
# @option options :prefix Prefix to put before the version (default = "html")
|
11
|
+
def call(release, options = {})
|
12
|
+
name = [(options[:prefix] || "html"), release.scm.version].join("-")
|
13
|
+
|
14
|
+
release.log(self, "Finalizing release to #{release.target_path + name}")
|
15
|
+
|
16
|
+
if File.exist?(release.target_path + name)
|
17
|
+
release.log(self, "Removing existing target #{release.target_path + name}")
|
18
|
+
FileUtils.rm_rf(release.target_path + name)
|
19
|
+
end
|
20
|
+
|
21
|
+
FileUtils.cp_r release.build_path, release.target_path + name
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module HtmlMockup::Release::Finalizers
|
2
|
+
class Base
|
3
|
+
def call(release, options = {})
|
4
|
+
raise ArgumentError, "Implement in subclass"
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
require File.dirname(__FILE__) + "/finalizers/zip"
|
10
|
+
require File.dirname(__FILE__) + "/finalizers/dir"
|
11
|
+
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'tilt'
|
2
|
+
module HtmlMockup
|
3
|
+
|
4
|
+
# Inject VERSION / DATE (i.e. in TOC)
|
5
|
+
# r.inject({"VERSION" => release.version, "DATE" => release.date}, :into => %w{_doc/toc.html})
|
6
|
+
|
7
|
+
# Inject CHANGELOG
|
8
|
+
# r.inject({"CHANGELOG" => {:file => "", :filter => BlueCloth}}, :into => %w{_doc/changelog.html})
|
9
|
+
|
10
|
+
class Release::Injector
|
11
|
+
|
12
|
+
# @example Simple variable injection (replaces [VARIABLE] into all .css files)
|
13
|
+
# {"[VARIABLE]" => "replacement"}, :into => %w{**/*.css}
|
14
|
+
#
|
15
|
+
# @example Regex variable injection (replaces all matches into test.js files)
|
16
|
+
# {/\/\*\s*\[BANNER\]\s*\*\// => "replacement"}, :into => %w{javacripts/test.js}
|
17
|
+
#
|
18
|
+
# @example Simple variable injection with filtering (replaces [VARIABLE] with :content run through the markdown processor into all .html files)
|
19
|
+
# {"[VARIABLE]" => {:content => "# header one", :processor => "md"}, :into => %w{**/*.html}
|
20
|
+
#
|
21
|
+
# @example Full file injection (replaces all matches of [CHANGELOG] with the contents of "CHANGELOG.md" into _doc/changelog.html)
|
22
|
+
#
|
23
|
+
# {"CHANGELOG" => {:file => "CHANGELOG.md"}}, :into => %w{_doc/changelog.html}
|
24
|
+
#
|
25
|
+
# @example Full file injection with filtering (replaces all matches of [CHANGELOG] with the contents of "CHANGELOG" which ran through Markdown compresser into _doc/changelog.html)
|
26
|
+
#
|
27
|
+
# {"CHANGELOG" => {:file => "CHANGELOG", :processor => "md"}}, :into => %w{_doc/changelog.html}
|
28
|
+
#
|
29
|
+
# Processors are based on Tilt (https://github.com/rtomayko/tilt).
|
30
|
+
# Currently supported/tested processors are:
|
31
|
+
#
|
32
|
+
# * 'md' for Markdown (bluecloth)
|
33
|
+
#
|
34
|
+
# Injection files are relative to the :source_path
|
35
|
+
#
|
36
|
+
# @param [Hash] variables Variables to inject. See example for more info
|
37
|
+
# @option options [Array] :into An array of file globs relative to the build_path
|
38
|
+
def initialize(variables, options)
|
39
|
+
@variables = variables
|
40
|
+
@into = options[:into]
|
41
|
+
end
|
42
|
+
|
43
|
+
def call(release)
|
44
|
+
files = release.get_files(@into)
|
45
|
+
|
46
|
+
files.each do |f|
|
47
|
+
c = File.read(f)
|
48
|
+
injected_vars = []
|
49
|
+
@variables.each do |variable, injection|
|
50
|
+
if c.gsub!(variable, get_content(injection, release))
|
51
|
+
injected_vars << variable
|
52
|
+
end
|
53
|
+
end
|
54
|
+
release.log(self, "Injected variables #{injected_vars.inspect} into #{f}") if injected_vars.size > 0
|
55
|
+
File.open(f,"w") { |fh| fh.write c }
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_content(injection, release)
|
61
|
+
case injection
|
62
|
+
when String
|
63
|
+
injection
|
64
|
+
when Hash
|
65
|
+
get_complex_injection(injection, release)
|
66
|
+
else
|
67
|
+
if injection.respond_to?(:to_s)
|
68
|
+
injection.to_s
|
69
|
+
else
|
70
|
+
raise ArgumentError, "Woah, what's this? #{injection.inspect}"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def get_complex_injection(injection, release)
|
76
|
+
|
77
|
+
if injection[:file]
|
78
|
+
content = File.read(release.source_path + injection[:file])
|
79
|
+
else
|
80
|
+
content = injection[:content]
|
81
|
+
end
|
82
|
+
|
83
|
+
raise ArgumentError, "No :content or :file specified" if !content
|
84
|
+
|
85
|
+
if injection[:processor]
|
86
|
+
if tmpl = Tilt[injection[:processor]]
|
87
|
+
(tmpl.new{ content }).render
|
88
|
+
else
|
89
|
+
raise ArgumentError, "Unknown processor #{injection[:processor]}"
|
90
|
+
end
|
91
|
+
else
|
92
|
+
content
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
module HtmlMockup::Release::Processors
|
3
|
+
class Requirejs < Base
|
4
|
+
|
5
|
+
# @option options [Hash] :build_files An a hash of files to build (as key) and the target directory in the release to put it as value, each one will be built in a separate directory. (default is {"javascripts/site.build.js" => "javascripts"})
|
6
|
+
# @option options [String] :node The system path for node (defaults to "node" in path)
|
7
|
+
# @option options [String] :rjs The system path to the requirejs optimizer (r.js) (defaults to "../vendor/requirejs/r.js" (relative to source_path))
|
8
|
+
def call(release, options={})
|
9
|
+
options = {
|
10
|
+
:build_files => {"javascripts/site.build.js" => "javascripts"},
|
11
|
+
:rjs => release.source_path + "../vendor/requirejs/r.js",
|
12
|
+
:node => "node"
|
13
|
+
}.update(options)
|
14
|
+
|
15
|
+
begin
|
16
|
+
`#{options[:node]} -v`
|
17
|
+
rescue Errno::ENOENT
|
18
|
+
raise RuntimeError, "Could not find node in #{node.inspect}"
|
19
|
+
end
|
20
|
+
|
21
|
+
if !File.exist?(options[:rjs])
|
22
|
+
raise RuntimeError, "Could not find r.js optimizer at #{options[:rjs].inspect}"
|
23
|
+
end
|
24
|
+
|
25
|
+
options[:build_files].each do |build_file, target|
|
26
|
+
build_file = release.build_path + build_file
|
27
|
+
target = release.build_path + target
|
28
|
+
release.log(self, "Optimizing #{build_file}")
|
29
|
+
|
30
|
+
# Hack to create tempfile in build
|
31
|
+
t = Tempfile.new("requirejs", release.build_path)
|
32
|
+
tmp_build_dir = t.path
|
33
|
+
t.close
|
34
|
+
t.unlink
|
35
|
+
|
36
|
+
# Run r.js optimizer
|
37
|
+
output = `#{options[:node]} #{options[:rjs]} -o #{build_file} dir=#{tmp_build_dir}`
|
38
|
+
|
39
|
+
# Check if r.js succeeded
|
40
|
+
unless $?.success?
|
41
|
+
raise RuntimeError, "Asset compilation with node failed.\nr.js output:\n #{output}"
|
42
|
+
end
|
43
|
+
|
44
|
+
if File.exist?(target)
|
45
|
+
release.log(self, "Removing target #{target}")
|
46
|
+
FileUtils.rm_rf(target)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Move the tmp_build_dir to target
|
50
|
+
FileUtils.mv(tmp_build_dir, target)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Use the sass gem
|
2
|
+
require 'sass'
|
3
|
+
|
4
|
+
module HtmlMockup::Release::Processors
|
5
|
+
class Sass < Base
|
6
|
+
# @param [Hash] options Options as described below, all other options will be passed to Sass.compile_file.
|
7
|
+
#
|
8
|
+
# @option options [Array] :match An array of shell globs, defaults to ["stylesheets/**/*.scss"]
|
9
|
+
# @option options [Array] :skip An array of regexps which will be skipped, defaults to [/_.*\.scss\Z/], Attention! Skipped files will be deleted as well!
|
10
|
+
def call(release, options={})
|
11
|
+
options = {
|
12
|
+
:match => ["stylesheets/**/*.scss"],
|
13
|
+
:skip => [/_.*\.scss\Z/],
|
14
|
+
:style => :expanded
|
15
|
+
}.update(options)
|
16
|
+
|
17
|
+
match = options.delete(:match)
|
18
|
+
skip = options.delete(:skip)
|
19
|
+
|
20
|
+
# Sassify SCSS files
|
21
|
+
files = release.get_files(match)
|
22
|
+
files.each do |f|
|
23
|
+
if !skip.detect{|r| r.match(f) }
|
24
|
+
release.log(self, "Processing: #{f}")
|
25
|
+
# Compile SCSS
|
26
|
+
::Sass.compile_file(f, f.gsub(/\.scss$/, ".css"), options)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Cleanup
|
31
|
+
files.each do |f|
|
32
|
+
# Remove source file
|
33
|
+
File.unlink(f)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|