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
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZmJiYTQ3MGRhMDdjM2QxZTE2MDU0N2NjYjcxNjdhZTJiNDk2ZGI1YQ==
5
+ data.tar.gz: !binary |-
6
+ OTlkMjZkNmM4YmViYmIwOGRjNjBiOTdkZjM2M2YzMGNmMjEyMzkzMg==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ ZTBjZDI1ZDFlOGVhZjU0ZjJjN2JjOWVhYjI0OWVlYjY3NTRhMmU5MDJmY2Zk
10
+ NTkxNzg5MzMxNjRiYTdlOWE3OTNiN2QwYmY3MzYxODc4ODExMWIyMGVjNWE0
11
+ YjBlZGM2Nzc2YzA1NDI1NzI0MzEzMTM0MTUxZjA5N2NjZGIxYjg=
12
+ data.tar.gz: !binary |-
13
+ ZjkxZTExOTdhNTZkM2RmNjljZGMwYmM4YWI1OWM5MDAxN2FhOGUwZjlhNGYw
14
+ NmEyNjE0NmFlNzExMmFjMDdmNGZkNDZiM2MzZmZhMWY4MTM3ZTVlZDFhZmQy
15
+ ZTA2Zjc3ZjA1OTdkNTBhM2VmMTE0MTc0OGQ5NmZhNzI3NmIzMzU=
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## Version 0.8.0
4
+ * Set content type header in response when rendering templates
5
+ * Add option to prompt user before performing rsync finalizer (defaults to true)
6
+ * Fix zip finalizer to use options[:zip] in actuall executed command too
7
+ * Logger now outputs color and has support for warning messages
8
+ * Mockup templating is now fully handled with Tilt
9
+ * Mockup extraction and URL relativization etc. for release are now done in their respective processors (will be added automatically if you haven't added them yourself.) This gives a fine-grained control over the point in time when these processors are ran.
10
+ * Add a testproject to the repository
11
+ * Add support for layouts
12
+ * Add a `git_branch` finalizer that allows us to release to a branch on a repository (this makes it easy to release github pages)
13
+ * Allow requirejs processor to work wih single files as well
14
+ * Expose server options to mockup so you can configure a https server if you want
15
+ * Minor fixes
16
+
3
17
  ## Version 0.7.4
4
18
  * Allow for underscores in .scss files when releasing
5
19
 
data/html_mockup.gemspec CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "html_mockup"
5
- s.version = "0.7.4"
5
+ s.version = "0.8.0"
6
6
 
7
- s.authors = ["Flurin Egger", "Edwin van der Graaf"]
7
+ s.authors = ["Flurin Egger", "Edwin van der Graaf", "Joran Kapteijns"]
8
8
  s.email = ["info@digitpaint.nl", "flurin@digitpaint.nl"]
9
9
  s.homepage = "http://github.com/digitpaint/html_mockup"
10
10
  s.summary = "HTML Mockup is a set of tools to create self-containing HTML mockups."
@@ -27,6 +27,7 @@ Gem::Specification.new do |s|
27
27
 
28
28
  s.add_dependency("thor", ["~> 0.16.0"])
29
29
  s.add_dependency("rack", [">= 1.0.0"])
30
- s.add_dependency("tilt", [">= 0"])
31
- s.add_dependency("hpricot", [">= 0.6.4"])
30
+ s.add_dependency("tilt", ["~> 1.4.0"])
31
+ s.add_dependency("sass", [">= 0"])
32
+ s.add_dependency("hpricot", [">= 0.6.4"])
32
33
  end
@@ -13,6 +13,13 @@ require File.dirname(__FILE__) + "/w3c_validator"
13
13
 
14
14
  module HtmlMockup
15
15
  class Cli < Thor
16
+
17
+ class_option :verbose,
18
+ :desc => "Set's verbose output",
19
+ :aliases => ["-v"],
20
+ :default => false,
21
+ :type => :boolean
22
+
16
23
  desc "serve [directory]","Serve directory as HTML, defaults to current directory"
17
24
  method_options :port => :string, # Defaults to 9000
18
25
  :html_path => :string, # The document root, defaults to "[directory]/html"
@@ -96,7 +103,7 @@ module HtmlMockup
96
103
 
97
104
  def banner(project)
98
105
  puts " Html: \"#{project.html_path}\""
99
- puts " Partials: \"#{project.partial_path}\" (#{HtmlMockup::Template.partial_files(project.partial_path).size} found)"
106
+ puts " Partials: \"#{project.partial_path}\""
100
107
  end
101
108
 
102
109
  # TODO: handle options
@@ -107,7 +114,7 @@ module HtmlMockup
107
114
  exit(1)
108
115
  end
109
116
 
110
- Project.new(path, options)
117
+ Project.new(path, {:shell => self.shell}.update(options))
111
118
  end
112
119
 
113
120
  def w3cvalidate(file)
@@ -119,7 +126,6 @@ module HtmlMockup
119
126
  end
120
127
  validator.valid
121
128
  end
122
-
123
129
 
124
130
  end
125
131
  end
@@ -2,6 +2,8 @@ require 'hpricot'
2
2
  require File.dirname(__FILE__) + '/resolver'
3
3
 
4
4
  module HtmlMockup
5
+
6
+ # @deprecated Don't use the extractor anymore, use release.use(:mockup, options) processor and release.use(:url_relativizer, options) processor
5
7
  class Extractor
6
8
 
7
9
  attr_reader :project, :target_path
@@ -59,7 +61,7 @@ module HtmlMockup
59
61
 
60
62
  # Runs the extractor on a single file and return processed source.
61
63
  def extract_source_from_file(file_path, env = {})
62
- source = HtmlMockup::Template.open(file_path, :partial_path => self.project.partial_path).render(env)
64
+ source = HtmlMockup::Template.open(file_path, :partials_path => self.project.partial_path, :layouts_path => self.project.layouts_path).render(env.dup)
63
65
 
64
66
  if @options[:url_relativize]
65
67
  source = relativize_urls(source, file_path)
@@ -0,0 +1,97 @@
1
+ require 'tilt'
2
+ require 'strscan'
3
+ require 'cgi'
4
+ require 'tilt/template'
5
+
6
+ module HtmlMockup
7
+
8
+ class MockupTemplate < Tilt::Template
9
+
10
+
11
+ class MissingPartial < StandardError; end
12
+
13
+
14
+ self.default_mime_type = 'text/html'
15
+
16
+ attr_reader :scanner
17
+
18
+ def self.engine_initialized?
19
+ true
20
+ end
21
+
22
+ def prepare
23
+
24
+ end
25
+
26
+ def evaluate(scope, locals, &block)
27
+ @scanner = StringScanner.new(data)
28
+ out = ""
29
+ while (partial = self.parse_partial_tag!) do
30
+ name, params, scanned = partial
31
+ # add new skipped content to output file
32
+ out << scanned
33
+
34
+ # scan until end of tag
35
+ current_content = self.scanner.scan_until(/<!-- \[STOP:#{name}\] -->/)
36
+ out << (render_partial(name, params, scope) || current_content)
37
+ end
38
+ out << scanner.rest
39
+
40
+ @output = out
41
+ end
42
+
43
+ protected
44
+
45
+ def parse_partial_tag!
46
+ params = {}
47
+ scanned = ""
48
+ begin_of_tag = self.scanner.scan_until(/<!-- \[START:/)
49
+ return nil unless begin_of_tag
50
+ scanned << begin_of_tag
51
+ scanned << tag = self.scanner.scan(/[a-z0-9_\/\-]+/)
52
+ if scanned_questionmark = self.scanner.scan(/\?/)
53
+ scanned << scanned_questionmark
54
+ scanned << raw_params = self.scanner.scan_until(/\] -->/)
55
+ raw_params.gsub!(/\] -->$/,"")
56
+
57
+ params = CGI.parse(raw_params)
58
+ params.keys.each{|k| params[k] = params[k].first }
59
+ else
60
+ scanned << self.scanner.scan_until(/\] -->/)
61
+ end
62
+
63
+ [tag,params,scanned]
64
+ end
65
+
66
+ def render_partial(name, params, scope)
67
+ if partial_template_path = scope.template.find_template(name, :partials_path)
68
+ # New style templates
69
+ out = (scope.partial(name, :locals => params) || current_content)
70
+ elsif partial_template_path = scope.template.find_template(name.to_s + ".part", :partials_path)
71
+ # Old style templates
72
+ template = Tilt::ERBTemplate.new(partial_template_path.to_s)
73
+ context = TemplateContext.new(params)
74
+ out = template.render(context, :env => scope.env)
75
+ else
76
+ # Not found
77
+ raise MissingPartial.new("Could not find partial '#{name}'")
78
+ end
79
+
80
+ "\n" + out.rstrip + "\n<!-- [STOP:#{name}] -->"
81
+ end
82
+
83
+ class TemplateContext
84
+ # Params will be set as instance variables
85
+ def initialize(params)
86
+ params.each do |k,v|
87
+ self.instance_variable_set("@#{k}",v)
88
+ end
89
+ end
90
+ end
91
+
92
+ end
93
+
94
+ end
95
+
96
+ Tilt.register HtmlMockup::MockupTemplate, "html"
97
+ Tilt.prefer HtmlMockup::MockupTemplate
@@ -10,24 +10,37 @@ module HtmlMockup
10
10
  # @attr :html_path [Pathname] The path of the HTML mockup
11
11
  # @attr :partial_path [Pathname] The path for the partials for this mockup
12
12
  # @attr :mockupfile [Mockupfile] The Mockupfile for this project
13
- attr_accessor :path, :html_path, :partial_path, :mockupfile
13
+ attr_accessor :path, :html_path, :partial_path, :layouts_path, :mockupfile
14
+
15
+ attr_accessor :shell
16
+
17
+ attr_accessor :options
14
18
 
15
19
  def initialize(path, options={})
16
20
  @path = Pathname.new(path)
17
21
 
18
22
  @options = {
19
23
  :html_path => @path + "html",
20
- :partial_path => @path + "partials"
21
- }.update(options)
24
+ :partial_path => @path + "partials",
25
+ :layouts_path => @path + "layouts"
26
+ }
22
27
 
23
- paths = mockup_paths(@options[:html_path], @options[:partial_path])
24
- self.html_path = paths[0]
25
- self.partial_path = paths[1]
28
+ # Clumsy string to symbol key conversion
29
+ options.each{|k,v| @options[k.is_a?(String) ? k.to_sym : k] = v }
30
+
31
+ self.html_path = @options[:html_path]
32
+ self.partial_path = @options[:partials_path] || @options[:partial_path] || self.html_path + "../partials/"
33
+ self.layouts_path = @options[:layouts_path]
34
+ self.shell = @options[:shell]
26
35
 
27
36
  @mockupfile = Mockupfile.new(self)
28
37
  @mockupfile.load
29
38
  end
30
39
 
40
+ def shell
41
+ @shell ||= Thor::Base.shell.new
42
+ end
43
+
31
44
  def server
32
45
  options = @options[:server] || {}
33
46
  @server ||= Server.new(self, options)
@@ -45,15 +58,12 @@ module HtmlMockup
45
58
  def partial_path=(p)
46
59
  @partial_path = Pathname.new(p).realpath
47
60
  end
48
-
49
- protected
61
+ alias :partials_path :partial_path
62
+ alias :partials_path= :partial_path=
50
63
 
51
- def mockup_paths(html_path, partial_path = nil)
52
- html_path = Pathname.new(html_path)
53
- partial_path = partial_path && Pathname.new(partial_path) || (html_path + "../partials/")
54
- [html_path, partial_path]
64
+ def layouts_path=(p)
65
+ @layouts_path = Pathname.new(p).realpath
55
66
  end
56
-
57
-
67
+
58
68
  end
59
69
  end
@@ -13,10 +13,9 @@ module HtmlMockup
13
13
 
14
14
  def initialize(project)
15
15
  @project = project
16
- root,partial_path = project.html_path, project.partial_path
16
+ @docroot = project.html_path
17
17
 
18
- @docroot = root
19
- @partial_path = partial_path
18
+ @resolver = Resolver.new(@docroot)
20
19
  @file_server = ::Rack::File.new(@docroot)
21
20
  end
22
21
 
@@ -24,25 +23,25 @@ module HtmlMockup
24
23
  url = env["PATH_INFO"]
25
24
  env["MOCKUP_PROJECT"] = project
26
25
 
27
- resolver = Resolver.new(@docroot)
28
-
29
- if template_path = resolver.url_to_path(url)
26
+ if template_path = @resolver.url_to_path(url)
30
27
  env["rack.errors"].puts "Rendering template #{template_path.inspect} (#{url.inspect})"
31
- begin
32
- templ = ::HtmlMockup::Template.open(template_path, :partial_path => @partial_path)
28
+ # begin
29
+ templ = ::HtmlMockup::Template.open(template_path, :partials_path => @project.partials_path, :layouts_path => @project.layouts_path)
30
+ mime = ::Rack::Mime.mime_type(File.extname(template_path), 'text/html')
33
31
  resp = ::Rack::Response.new do |res|
32
+ res.headers["Content-Type"] = mime if mime
34
33
  res.status = 200
35
34
  res.write templ.render(env)
36
35
  end
37
36
  resp.finish
38
- rescue StandardError => e
39
- env["rack.errors"].puts " #{e.message}"
40
- resp = ::Rack::Response.new do |res|
41
- res.status = 500
42
- res.write "An error occurred"
43
- end
44
- resp.finish
45
- end
37
+ # rescue StandardError => e
38
+ # env["rack.errors"].puts "#{e.message}\n #{e.backtrace.join("\n")}\n\n"
39
+ # resp = ::Rack::Response.new do |res|
40
+ # res.status = 500
41
+ # res.write "An error occurred"
42
+ # end
43
+ # resp.finish
44
+ # end
46
45
  else
47
46
  env["rack.errors"].puts "Invoking file handler for #{url.inspect}"
48
47
  @file_server.call(env)
@@ -192,8 +192,9 @@ module HtmlMockup
192
192
  #
193
193
  # @param Hash options Options hash passed to extractor
194
194
  #
195
- # @see HtmlMockup::Extractor for more information
195
+ # @deprecated Don't use the extractor anymore, use release.use(:mockup, options) processor
196
196
  def extract(options = {})
197
+ self.warn(self, "Don't use the extractor anymore, use release.use(:mockup, options) and release.use(:url_relativizer, options) processors")
197
198
  @extractor_options = options
198
199
  end
199
200
 
@@ -202,8 +203,10 @@ module HtmlMockup
202
203
  # Validate paths
203
204
  validate_paths!
204
205
 
205
- # Extract valid mockup
206
- run_extractor!
206
+ # Extract mockup
207
+ copy_source_path_to_build_path!
208
+
209
+ validate_stack!
207
210
 
208
211
  # Run stack
209
212
  run_stack!
@@ -216,10 +219,31 @@ module HtmlMockup
216
219
 
217
220
  end
218
221
 
219
- def log(part, msg)
220
- puts part.class.to_s + " : " + msg.to_s
222
+ # Write out a log message
223
+ def log(part, msg, verbose = false, &block)
224
+ if !verbose || verbose && self.project.options[:verbose]
225
+ self.project.shell.say "\033[37m#{part.class.to_s}\033[0m" + " : " + msg.to_s, nil, true
226
+ end
227
+ if block_given?
228
+ begin
229
+ self.project.shell.padding = self.project.shell.padding + 1
230
+ yield
231
+ ensure
232
+ self.project.shell.padding = self.project.shell.padding - 1
233
+ end
234
+ end
235
+ end
236
+
237
+ def debug(part, msg, &block)
238
+ self.log(part, msg, true, &block)
239
+ end
240
+
241
+ # Write out a warning message
242
+ def warn(part, msg)
243
+ self.project.shell.say "\033[37m#{part.class.to_s}\033[0m" + " : " + "\033[31m#{msg.to_s}\033[0m", nil, true
221
244
  end
222
245
 
246
+
223
247
  # @param [Array] globs an array of file path globs that will be globbed against the build_path
224
248
  # @param [Array] excludes an array of regexps that will be excluded from the result
225
249
  def get_files(globs, excludes = [])
@@ -237,6 +261,8 @@ module HtmlMockup
237
261
  # = The runway =
238
262
  # ==============
239
263
 
264
+ # Checks if build path exists (and cleans it up)
265
+ # Checks if target path exists (if not, creates it)
240
266
  def validate_paths!
241
267
  if self.build_path.exist?
242
268
  log self, "Cleaning up previous build \"#{self.build_path}\""
@@ -249,9 +275,28 @@ module HtmlMockup
249
275
  end
250
276
  end
251
277
 
252
- def run_extractor!
253
- extractor = Extractor.new(self.project, self.build_path, @extractor_options)
254
- extractor.run!
278
+ # Checks if deprecated extractor options have been set
279
+ # Checks if the mockup will be runned
280
+ def validate_stack!
281
+
282
+ mockup_options = {}
283
+ relativizer_options = {}
284
+ run_relativizer = true
285
+ if @extractor_options
286
+ mockup_options = {:env => @extractor_options[:env]}
287
+ relativizer_options = {:url_attributes => @extractor_options[:url_attributes]}
288
+ run_relativizer = @extractor_options[:url_relativize]
289
+ end
290
+
291
+ unless @stack.find{|(processor, options)| processor.class == HtmlMockup::Release::Processors::Mockup }
292
+ @stack.unshift([HtmlMockup::Release::Processors::UrlRelativizer.new, relativizer_options])
293
+ @stack.unshift([HtmlMockup::Release::Processors::Mockup.new, mockup_options])
294
+ end
295
+ end
296
+
297
+ def copy_source_path_to_build_path!
298
+ mkdir(self.build_path)
299
+ cp_r(self.source_path.children, self.build_path)
255
300
  end
256
301
 
257
302
  def run_stack!
@@ -15,4 +15,5 @@ end
15
15
  require File.dirname(__FILE__) + "/finalizers/zip"
16
16
  require File.dirname(__FILE__) + "/finalizers/dir"
17
17
  require File.dirname(__FILE__) + "/finalizers/rsync"
18
+ require File.dirname(__FILE__) + "/finalizers/git_branch"
18
19
 
@@ -0,0 +1,92 @@
1
+ # Finalizes the release into a specific branch of a repository and pushes it
2
+ #
3
+ class GitBranch < HtmlMockup::Release::Finalizers::Base
4
+
5
+ # @param Hash options The options
6
+ #
7
+ # @option options String :remote The remote repository (default is the origin of the current repository)
8
+ # @option options String :branch The remote branch (default is "gh-pages")
9
+ # @option options Boolean :cleanup Cleanup temp dir afterwards (default is true)
10
+ # @option options Boolean :push Push to remote (default is true)
11
+ def initialize(options={})
12
+ @options = {
13
+ :remote => nil,
14
+ :branch => "gh-pages",
15
+ :cleanup => true,
16
+ :push => true
17
+ }
18
+ end
19
+
20
+
21
+ def call(release, options = {})
22
+ options = @options.dup.update(options)
23
+ git_dir = find_git_dir(release.project.path)
24
+
25
+ # 0. Get remote
26
+ unless remote = (options[:remote] || `git --git-dir=#{git_dir} config --get remote.origin.url`).strip
27
+ raise "No remote found for origin"
28
+ end
29
+
30
+ e_remote = Shellwords.escape(remote)
31
+ e_branch = Shellwords.escape(options[:branch])
32
+
33
+ tmp_dir = Pathname.new(Dir.mktmpdir)
34
+ clone_dir = tmp_dir + "clone"
35
+
36
+ # Check if remote already has branch
37
+ if `git ls-remote --heads #{e_remote} refs/heads/#{e_branch}` == ""
38
+ release.log(self, "Creating empty branch")
39
+ # Branch does not exist yet
40
+ FileUtils.mkdir(clone_dir)
41
+ Dir.chdir(clone_dir) do
42
+ `git init`
43
+ `git remote add origin #{e_remote}`
44
+ `git checkout -b #{e_branch}`
45
+ end
46
+ else
47
+ release.log(self, "Cloning existing repo")
48
+ # 1. Clone into different directory
49
+ `git clone #{e_remote} --branch #{e_branch} --single-branch #{clone_dir}`
50
+ end
51
+
52
+ release.log(self, "Working git magic in #{clone_dir}")
53
+ Dir.chdir(clone_dir) do
54
+ # 3. Copy changes
55
+ FileUtils.rm_rf("*")
56
+ FileUtils.cp_r release.build_path.to_s + "/.", clone_dir.to_s
57
+
58
+ # 4. Add all files
59
+ `git add .`
60
+
61
+ # 5. Commit
62
+ `git commit -a -m "Release #{release.scm.version}"`
63
+
64
+ # 6. Git push
65
+ if options[:push]
66
+ `git push origin #{e_branch}`
67
+ end
68
+ end
69
+
70
+ if options[:cleanup]
71
+ FileUtils.rm_rf(tmp_dir)
72
+ end
73
+
74
+ end
75
+
76
+ protected
77
+
78
+ # Find the git dir
79
+ # TODO this is just a copy from release/scm/git.rb
80
+ def find_git_dir(path)
81
+ path = Pathname.new(path).realpath
82
+ while path.parent != path && !(path + ".git").directory?
83
+ path = path.parent
84
+ end
85
+
86
+ path = path + ".git"
87
+
88
+ raise "Could not find suitable .git dir in #{path}" if !path.directory?
89
+
90
+ path
91
+ end
92
+ end