html_mockup 0.7.4 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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