html_mockup 0.7.4 → 0.8.0

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.
Files changed (38) hide show
  1. checksums.yaml +15 -0
  2. data/CHANGELOG.md +14 -0
  3. data/html_mockup.gemspec +5 -4
  4. data/lib/html_mockup/cli.rb +9 -3
  5. data/lib/html_mockup/extractor.rb +3 -1
  6. data/lib/html_mockup/mockup_template.rb +97 -0
  7. data/lib/html_mockup/project.rb +24 -14
  8. data/lib/html_mockup/rack/html_mockup.rb +15 -16
  9. data/lib/html_mockup/release.rb +53 -8
  10. data/lib/html_mockup/release/finalizers.rb +1 -0
  11. data/lib/html_mockup/release/finalizers/git_branch.rb +92 -0
  12. data/lib/html_mockup/release/finalizers/rsync.rb +34 -27
  13. data/lib/html_mockup/release/finalizers/zip.rb +1 -1
  14. data/lib/html_mockup/release/processors.rb +2 -0
  15. data/lib/html_mockup/release/processors/mockup.rb +87 -0
  16. data/lib/html_mockup/release/processors/requirejs.rb +29 -5
  17. data/lib/html_mockup/release/processors/url_relativizer.rb +44 -0
  18. data/lib/html_mockup/release/processors/yuicompressor.rb +4 -2
  19. data/lib/html_mockup/resolver.rb +23 -22
  20. data/lib/html_mockup/server.rb +11 -10
  21. data/lib/html_mockup/template.rb +100 -111
  22. data/test/project/.rvmrc +1 -0
  23. data/test/project/Gemfile +6 -0
  24. data/test/project/Gemfile.lock +35 -0
  25. data/test/project/Mockupfile +7 -0
  26. data/test/project/html/formats/erb.html.erb +5 -0
  27. data/test/project/html/formats/markdown.md +3 -0
  28. data/test/project/html/formats/mockup.html +5 -0
  29. data/test/project/html/front_matter/erb.html.erb +16 -0
  30. data/test/project/html/front_matter/markdown.md +7 -0
  31. data/test/project/html/layouts/erb.html.erb +19 -0
  32. data/test/project/html/partials/erb.html.erb +10 -0
  33. data/test/project/html/partials/mockup.html +13 -0
  34. data/test/project/layouts/test.html.erb +27 -0
  35. data/test/project/partials/test/erb.html.erb +1 -0
  36. data/test/project/partials/test/markdown.md +1 -0
  37. data/test/project/partials/test/mockup.part.html +1 -0
  38. metadata +80 -19
@@ -14,12 +14,14 @@ module HtmlMockup::Release::Finalizers
14
14
  # @option options String :remote_path The remote path to upload to
15
15
  # @option options String :host The remote host to upload to
16
16
  # @option options String :username The remote username to upload to
17
+ # @option options Boolean :ask Prompt the user before uploading (default is true)
17
18
  def initialize(options = {})
18
19
  @options = {
19
20
  :rsync => "rsync",
20
21
  :remote_path => "",
21
22
  :host => "",
22
- :username => ""
23
+ :username => "",
24
+ :ask => true
23
25
  }.update(options)
24
26
  end
25
27
 
@@ -28,36 +30,36 @@ module HtmlMockup::Release::Finalizers
28
30
 
29
31
  # Validate options
30
32
  validate_options!(release, options)
31
-
32
- begin
33
- `#{@options[:rsync]} --version`
34
- rescue Errno::ENOENT
35
- raise RuntimeError, "Could not find rsync in #{@options[:rsync].inspect}"
36
- end
37
-
38
-
39
- local_path = release.build_path.to_s
40
- remote_path = options[:remote_path]
41
-
42
- local_path += "/" unless local_path =~ /\/\Z/
43
- remote_path += "/" unless remote_path =~ /\/\Z/
44
-
45
- release.log(self, "Starting upload of #{(release.build_path + "*")} to #{options[:host]}")
46
-
47
- command = "#{options[:rsync]} -az #{Shellwords.escape(local_path)} #{Shellwords.escape(options[:username])}@#{Shellwords.escape(options[:host])}:#{Shellwords.escape(remote_path)}"
48
-
49
- # Run r.js optimizer
50
- output = `#{command}`
33
+
34
+ if !options[:ask] || (prompt("Do you wish to upload to #{options[:host]}? Anything other than 'yes' will cancel: ")) == 'yes'
35
+ begin
36
+ `#{@options[:rsync]} --version`
37
+ rescue Errno::ENOENT
38
+ raise RuntimeError, "Could not find rsync in #{@options[:rsync].inspect}"
39
+ end
51
40
 
52
- # Check if r.js succeeded
53
- unless $?.success?
54
- raise RuntimeError, "Rsync failed.\noutput:\n #{output}"
55
- end
41
+ local_path = release.build_path.to_s
42
+ remote_path = options[:remote_path]
43
+
44
+ local_path += "/" unless local_path =~ /\/\Z/
45
+ remote_path += "/" unless remote_path =~ /\/\Z/
56
46
 
47
+ release.log(self, "Starting upload of #{(release.build_path + "*")} to #{options[:host]}")
48
+
49
+ command = "#{options[:rsync]} -az #{Shellwords.escape(local_path)} #{Shellwords.escape(options[:username])}@#{Shellwords.escape(options[:host])}:#{Shellwords.escape(remote_path)}"
50
+
51
+ # Run r.js optimizer
52
+ output = `#{command}`
53
+
54
+ # Check if r.js succeeded
55
+ unless $?.success?
56
+ raise RuntimeError, "Rsync failed.\noutput:\n #{output}"
57
+ end
58
+ end
57
59
  end
58
-
60
+
59
61
  protected
60
-
62
+
61
63
  def validate_options!(release, options)
62
64
  must_have_keys = [:remote_path, :host, :username]
63
65
  if (options.keys & must_have_keys).size != must_have_keys.size
@@ -65,6 +67,11 @@ module HtmlMockup::Release::Finalizers
65
67
  raise "Missing keys: #{(must_have_keys - options.keys).inspect}"
66
68
  end
67
69
  end
70
+
71
+ def prompt(question = 'Do you wish to continue?')
72
+ print(question)
73
+ return $stdin.gets.strip
74
+ end
68
75
 
69
76
  end
70
77
  end
@@ -33,7 +33,7 @@ module HtmlMockup::Release::Finalizers
33
33
  end
34
34
 
35
35
  ::Dir.chdir(release.build_path) do
36
- `zip -r -9 "#{release.target_path + name}" ./*`
36
+ `#{options[:zip]} -r -9 "#{release.target_path + name}" ./*`
37
37
  end
38
38
  end
39
39
 
@@ -13,6 +13,8 @@ module HtmlMockup::Release::Processors
13
13
  end
14
14
  end
15
15
 
16
+ require File.dirname(__FILE__) + "/processors/mockup"
17
+ require File.dirname(__FILE__) + "/processors/url_relativizer"
16
18
  require File.dirname(__FILE__) + "/processors/requirejs"
17
19
  require File.dirname(__FILE__) + "/processors/sass"
18
20
  require File.dirname(__FILE__) + "/processors/yuicompressor"
@@ -0,0 +1,87 @@
1
+ module HtmlMockup::Release::Processors
2
+ class Mockup < Base
3
+
4
+ attr_accessor :project
5
+
6
+ def initialize(options={})
7
+ @options = {
8
+ :env => {},
9
+ :match => ["**/*.{html,md,html.erb}"],
10
+ :skip => [/\Astylesheets/, /\Ajavascripts/]
11
+ }
12
+
13
+ @options.update(options) if options
14
+ end
15
+
16
+ def call(release, options={})
17
+ self.project = release.project
18
+
19
+ options = {}.update(@options).update(options)
20
+
21
+ options[:env].update("MOCKUP_PROJECT" => project)
22
+
23
+ release.log(self, "Processing mockup files")
24
+
25
+ release.get_files(options[:match], options[:skip]).each do |file_path|
26
+ self.run_on_file!(file_path, @options[:env])
27
+ end
28
+ end
29
+
30
+
31
+ def run_on_file!(file_path, env = {})
32
+ template = HtmlMockup::Template.open(file_path, :partials_path => self.project.partial_path, :layouts_path => self.project.layouts_path)
33
+
34
+ # Clean up source file
35
+ FileUtils.rm(file_path)
36
+
37
+ # Write out new file
38
+ File.open(self.target_path(file_path, template),"w"){|f| f.write(template.render(env.dup)) }
39
+ end
40
+
41
+ # Runs the extractor on a single file and return processed source.
42
+ def extract_source_from_file(file_path, env = {})
43
+ HtmlMockup::Template.open(file_path, :partials_path => self.project.partial_path, :layouts_path => self.project.layouts_path).render(env.dup)
44
+ end
45
+
46
+ protected
47
+
48
+ def target_path(path, template)
49
+ # 1. If we have a double extension we rip of the template it's own extension and be done with it
50
+ parts = File.basename(path.to_s).split(".")
51
+ dir = Pathname.new(File.dirname(path.to_s))
52
+
53
+ # 2. Try to figure out the extension based on the template's mime-type
54
+ mime_types = {
55
+ "text/html" => "html",
56
+ "text/css" => "css",
57
+ "application/javascript" => "js",
58
+ "text/xml" => "xml",
59
+ "application/xml" => "xml",
60
+ "text/csv" => "csv",
61
+ "application/json" => "json"
62
+ }
63
+ extension = mime_types[template.template.class.default_mime_type]
64
+
65
+ # Always return .html directly as it will cause too much trouble otherwise
66
+ if parts.last == "html"
67
+ return path
68
+ end
69
+
70
+ if parts.size > 2
71
+ # Strip extension
72
+ dir + parts[0..-2].join(".")
73
+ else
74
+ return path if extension.nil?
75
+
76
+ if parts.size > 1
77
+ # Strip extension and replace with extension
78
+ dir + (parts[0..-2] << extension).join(".")
79
+ else
80
+ # Let's just add the extension
81
+ dir + (parts << extension).join(".")
82
+ end
83
+ end
84
+ end
85
+
86
+ end
87
+ end
@@ -4,14 +4,14 @@ module HtmlMockup::Release::Processors
4
4
 
5
5
  def initialize(options = {})
6
6
  @options = {
7
- :build_files => {"javascripts/site.build.js" => "javascripts"},
7
+ :build_files => {"javascripts/site.build.js" => {:dir => "javascripts"}},
8
8
  :rjs => "r.js",
9
9
  :node => "node"
10
10
  }.update(options)
11
11
  end
12
12
 
13
13
 
14
- # @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"})
14
+ # @option options [Hash] :build_files An a hash of files to build (as key) and the target as a hash with either {:dir => "STRING"} or {:file => "STRING"} in the release to put it as value, each one will be built in a separate directory. (default is {"javascripts/site.build.js" => {:dir => "javascripts"}})
15
15
  # @option options [String] :node The system path for node (defaults to "node" in path)
16
16
  # @option options [String] :rjs The system path to the requirejs optimizer (r.js) (defaults to "../vendor/requirejs/r.js" (relative to source_path))
17
17
  def call(release, options={})
@@ -27,7 +27,21 @@ module HtmlMockup::Release::Processors
27
27
 
28
28
  @options[:build_files].each do |build_file, target|
29
29
  build_file = release.build_path + build_file
30
- target = release.build_path + target
30
+
31
+ if target.kind_of?(Hash)
32
+ if target[:dir]
33
+ target = target[:dir]
34
+ target_type = :dir
35
+ elsif target[:file]
36
+ target = target[:file]
37
+ target_type = :file
38
+ end
39
+ else
40
+ # Old style
41
+ target_type = :dir
42
+ end
43
+
44
+ target = release.build_path + target
31
45
  release.log(self, "Optimizing #{build_file}")
32
46
 
33
47
  # Hack to create tempfile in build
@@ -37,7 +51,13 @@ module HtmlMockup::Release::Processors
37
51
  t.unlink
38
52
 
39
53
  # Run r.js optimizer
40
- output = `#{rjs_command} -o #{build_file} dir=#{tmp_build_dir}`
54
+ if target_type == :dir
55
+ output = `#{rjs_command} -o #{build_file} dir=#{tmp_build_dir}`
56
+ else
57
+ output = `#{rjs_command} -o #{build_file} out=#{tmp_build_dir}/out.js`
58
+ end
59
+
60
+ release.debug(self, output)
41
61
 
42
62
  # Check if r.js succeeded
43
63
  unless $?.success?
@@ -50,7 +70,11 @@ module HtmlMockup::Release::Processors
50
70
  end
51
71
 
52
72
  # Move the tmp_build_dir to target
53
- FileUtils.mv(tmp_build_dir, target)
73
+ if target_type == :dir
74
+ FileUtils.mv(tmp_build_dir, target)
75
+ end
76
+ FileUtils.mv("#{tmp_build_dir}/out.js", target)
77
+ FileUtils.rm_rf(tmp_build_dir)
54
78
  end
55
79
  end
56
80
 
@@ -0,0 +1,44 @@
1
+ require File.dirname(__FILE__) + '../../../resolver'
2
+
3
+ module HtmlMockup::Release::Processors
4
+ class UrlRelativizer < Base
5
+
6
+ def initialize(options={})
7
+ @options = {
8
+ :url_attributes => %w{src href action},
9
+ :match => ["**/*.html"]
10
+ }
11
+
12
+ @options.update(options) if options
13
+ end
14
+
15
+ def call(release, options={})
16
+ options = {}.update(@options).update(options)
17
+
18
+ release.log(self, "Relativizing all URLS in #{options[:match].inspect} files in attributes #{options[:url_attributes].inspect}")
19
+
20
+ @resolver = HtmlMockup::Resolver.new(release.build_path)
21
+ release.get_files(options[:match]).each do |file_path|
22
+ release.debug(self, "Relativizing URLS in #{file_path}") do
23
+ orig_source = File.read(file_path)
24
+ File.open(file_path,"w") do |f|
25
+ doc = Hpricot(orig_source)
26
+ options[:url_attributes].each do |attribute|
27
+ (doc/"*[@#{attribute}]").each do |tag|
28
+ converted_url = @resolver.url_to_relative_url(tag[attribute], file_path)
29
+ release.debug(self, "Converting '#{tag[attribute]}' to '#{converted_url}'")
30
+ case converted_url
31
+ when String
32
+ tag[attribute] = converted_url
33
+ when nil
34
+ release.log(self, "Could not resolve link #{tag[attribute]} in #{file_path}")
35
+ end
36
+ end
37
+ end
38
+ f.write(doc.to_original_html)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -24,6 +24,8 @@ module HtmlMockup::Release::Processors
24
24
  css_compressor = YUI::CssCompressor.new(compressor_options)
25
25
  js_compressor = YUI::JavaScriptCompressor.new(compressor_options)
26
26
 
27
+ release.log self, "Minifying #{options[:match].inspect}"
28
+
27
29
  # Add version numbers and minify the files
28
30
  release.get_files(options[:match], options[:skip]).each do |f|
29
31
  type = f[/\.([^.]+)\Z/,1]
@@ -36,14 +38,14 @@ module HtmlMockup::Release::Processors
36
38
  minified = [header]
37
39
 
38
40
  # Actual minification
39
- release.log self, "Minifying #{f}"
41
+ release.debug self, "Minifying #{f}"
40
42
  case type
41
43
  when "css"
42
44
  minified << css_compressor.compress(data)
43
45
  when "js"
44
46
  minified << js_compressor.compress(data)
45
47
  else
46
- release.log self, "Error minifying: encountered unknown type \"#{type}\""
48
+ release.warn self, "Error minifying: encountered unknown type \"#{type}\""
47
49
  minified << data
48
50
  end
49
51
 
@@ -2,37 +2,38 @@ module HtmlMockup
2
2
  class Resolver
3
3
 
4
4
  def initialize(path)
5
+ raise ArgumentError, "Resolver base path can't be nil" if path.nil?
5
6
  @base = Pathname.new(path)
6
7
  end
7
8
 
8
- def url_to_path(url, exact_match = false)
9
+ # @param [String] url The url to resolve to a path
10
+ # @param [true,false] exact_match Wether or not to match exact paths, this is mainly used in the path_to_url method to match .js, .css, etc files.
11
+ def find_template(url, exact_match = false)
9
12
  path, qs, anch = strip_query_string_and_anchor(url.to_s)
10
13
 
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
14
+ path = File.join(@base, path)
15
+
16
+ if exact_match && File.exist?(path)
17
+ return Pathname.new(path)
18
+ end
19
+
20
+ # It's a directory, add "/index"
21
+ if File.directory?(path)
22
+ path = File.join(path, "index")
23
+ end
24
+
25
+ # 2. If it's .html,we strip of the extension
26
+ if path =~ /\.html\Z/
27
+ path.sub!(/\.html\Z/, "")
30
28
  end
31
29
 
32
- if file = search_files.find{|p| File.exist?(p) }
33
- Pathname.new(file)
30
+ extensions = Tilt.mappings.keys + Tilt.mappings.keys.map{|ext| "html.#{ext}"}
31
+
32
+ if found_extension = extensions.find { |ext| File.exist?(path + "." + ext) }
33
+ Pathname.new(path + "." + found_extension)
34
34
  end
35
35
  end
36
+ alias :url_to_path :find_template
36
37
 
37
38
 
38
39
  # Convert a disk path on file to an url
@@ -4,10 +4,13 @@ require File.dirname(__FILE__) + "/w3c_validator"
4
4
  require File.dirname(__FILE__) + "/rack/html_mockup"
5
5
  require File.dirname(__FILE__) + "/rack/html_validator"
6
6
 
7
+ require 'webrick'
8
+ require 'webrick/https'
9
+
7
10
  module HtmlMockup
8
11
  class Server
9
12
 
10
- attr_reader :options
13
+ attr_reader :options, :server_options
11
14
 
12
15
  attr_reader :project
13
16
 
@@ -18,6 +21,8 @@ module HtmlMockup
18
21
 
19
22
  @project = project
20
23
 
24
+ @server_options = {}
25
+
21
26
  set_options(options)
22
27
  end
23
28
 
@@ -28,7 +33,7 @@ module HtmlMockup
28
33
  :handler => nil, # Autodetect
29
34
  :port => 9000
30
35
  }.update(options)
31
-
36
+
32
37
  self.port = @options[:port]
33
38
  self.handler = @options[:handler]
34
39
  end
@@ -57,6 +62,10 @@ module HtmlMockup
57
62
  end
58
63
  end
59
64
  alias :run :run!
65
+
66
+ def port=(p)
67
+ self.server_options[:Port] = p
68
+ end
60
69
 
61
70
  protected
62
71
 
@@ -104,13 +113,5 @@ module HtmlMockup
104
113
  handler
105
114
  end
106
115
 
107
-
108
- # Generate server options for handler
109
- def server_options
110
- {
111
- :Port => self.port
112
- }
113
- end
114
-
115
116
  end
116
117
  end