roger 1.1.3 → 1.2.1

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 (76) hide show
  1. checksums.yaml +4 -4
  2. data/.hound.yml +2 -0
  3. data/.rubocop.yml +47 -0
  4. data/.travis.yml +1 -5
  5. data/CHANGELOG.md +8 -0
  6. data/Gemfile +3 -3
  7. data/Rakefile +10 -4
  8. data/bin/roger +1 -1
  9. data/doc/mockupfile.md +97 -0
  10. data/doc/templating.md +5 -1
  11. data/examples/default_template/Gemfile +1 -1
  12. data/lib/roger/cli.rb +41 -36
  13. data/lib/roger/cli/command.rb +2 -4
  14. data/lib/roger/cli/generate.rb +1 -0
  15. data/lib/roger/cli/release.rb +2 -2
  16. data/lib/roger/cli/serve.rb +11 -11
  17. data/lib/roger/cli/test.rb +6 -5
  18. data/lib/roger/extractor.rb +42 -43
  19. data/lib/roger/generators.rb +27 -19
  20. data/lib/roger/generators/generator.rb +7 -10
  21. data/lib/roger/generators/new.rb +56 -41
  22. data/lib/roger/generators/templates/generator.tt +5 -5
  23. data/lib/roger/helpers/get_callable.rb +15 -14
  24. data/lib/roger/helpers/logging.rb +35 -13
  25. data/lib/roger/mockupfile.rb +13 -23
  26. data/lib/roger/project.rb +41 -34
  27. data/lib/roger/rack/roger.rb +28 -29
  28. data/lib/roger/rack/sleep.rb +4 -5
  29. data/lib/roger/release.rb +95 -72
  30. data/lib/roger/release/cleaner.rb +14 -13
  31. data/lib/roger/release/finalizers.rb +10 -10
  32. data/lib/roger/release/finalizers/dir.rb +17 -19
  33. data/lib/roger/release/finalizers/git_branch.rb +76 -38
  34. data/lib/roger/release/finalizers/rsync.rb +60 -49
  35. data/lib/roger/release/finalizers/zip.rb +32 -29
  36. data/lib/roger/release/injector.rb +43 -37
  37. data/lib/roger/release/processors.rb +24 -22
  38. data/lib/roger/release/processors/mockup.rb +97 -69
  39. data/lib/roger/release/processors/url_relativizer.rb +57 -30
  40. data/lib/roger/release/scm.rb +30 -27
  41. data/lib/roger/release/scm/git.rb +101 -92
  42. data/lib/roger/resolver.rb +86 -61
  43. data/lib/roger/server.rb +52 -27
  44. data/lib/roger/template.rb +102 -74
  45. data/lib/roger/test.rb +16 -13
  46. data/lib/roger/version.rb +3 -2
  47. data/roger.gemspec +9 -5
  48. data/test/helpers/cli.rb +17 -15
  49. data/test/project/Gemfile +2 -2
  50. data/test/project/html/formats/csv.rcsv +0 -0
  51. data/test/project/lib/generators/test.rb +2 -3
  52. data/test/project/lib/tests/fail/fail.rb +5 -6
  53. data/test/project/lib/tests/noop/lib/cli.rb +2 -1
  54. data/test/project/lib/tests/noop/lib/test.rb +5 -5
  55. data/test/project/lib/tests/noop/noop.rb +2 -1
  56. data/test/project/lib/tests/succeed/succeed.rb +5 -6
  57. data/test/unit/cli/cli_base_test.rb +2 -3
  58. data/test/unit/cli/cli_generate_test.rb +9 -10
  59. data/test/unit/cli/cli_serve_test.rb +22 -18
  60. data/test/unit/cli/cli_test_test.rb +13 -15
  61. data/test/unit/cli/cli_version_test.rb +4 -4
  62. data/test/unit/generators_test.rb +8 -10
  63. data/test/unit/helpers/logging_test.rb +64 -0
  64. data/test/unit/rack/roger_test.rb +21 -0
  65. data/test/unit/release/cleaner_test.rb +23 -19
  66. data/test/unit/release/finalizers/git_branch_test.rb +2 -1
  67. data/test/unit/release/finalizers/zip_test.rb +48 -0
  68. data/test/unit/release/mockup_test.rb +48 -0
  69. data/test/unit/release/processors_test.rb +19 -19
  70. data/test/unit/release_test.rb +15 -14
  71. data/test/unit/resolver_test.rb +21 -14
  72. data/test/unit/server_test.rb +31 -0
  73. data/test/unit/template_test.rb +58 -36
  74. data/test/unit/test_test.rb +3 -2
  75. metadata +35 -9
  76. data/test/Mockupfile-syntax.rb +0 -93
@@ -1,16 +1,17 @@
1
1
  module Roger
2
+ # The test command and all it's children
2
3
  class Cli::Test < Thor
3
4
  def self.exit_on_failure?
4
5
  true
5
6
  end
6
7
 
7
- default_task :all
8
+ default_task :all
8
9
 
9
10
  desc "all", "Run all tests defined in Mockupfile. (this is the default action)"
10
11
  def all
11
- unless Cli::Base.project.test.run!
12
- raise Thor::Error, "Test failed"
13
- end
12
+ # If we use fail here the test breaks; no idea why
13
+ # rubocop:disable Style/SignalException:
14
+ raise(Thor::Error, "Test failed") unless Cli::Base.project.test.run!
14
15
  end
15
16
  end
16
- end
17
+ end
@@ -1,84 +1,84 @@
1
- require 'hpricot'
2
- require File.dirname(__FILE__) + '/resolver'
1
+ require "hpricot"
2
+ require File.dirname(__FILE__) + "/resolver"
3
3
 
4
4
  module Roger
5
-
6
- # @deprecated Don't use the extractor anymore, use release.use(:mockup, options) processor and release.use(:url_relativizer, options) processor
5
+ # @deprecated Don't use the extractor anymore, use release.use(:mockup, options) processor and
6
+ # release.use(:url_relativizer, options) processor
7
7
  class Extractor
8
-
9
8
  attr_reader :project, :target_path
10
-
11
-
9
+
12
10
  # @param [Project] project Project object
13
11
  # @param [String,Pathname] target_path Path to extract to
14
12
  # @param [Hash] options Options hash
15
-
13
+
16
14
  # @option options [Array] :url_attributes The element attributes to parse and relativize
17
15
  # @option options [Array] :url_relativize Wether or not we should relativize
18
16
  # @option options [Array] :env ENV variable to pass to template renderer.
19
- def initialize(project, target_path, options={})
17
+ def initialize(project, target_path, options = {})
20
18
  @project = project
21
19
  @target_path = Pathname.new(target_path)
22
20
  @resolver = Resolver.new(self.target_path)
23
-
24
-
21
+
25
22
  @options = {
26
- :url_attributes => %w{src href action},
27
- :url_relativize => true,
28
- :env => {}
23
+ url_attributes: %w(src href action),
24
+ url_relativize: true,
25
+ env: {}
29
26
  }
30
-
27
+
31
28
  @options.update(options) if options
32
-
29
+
33
30
  @options[:env].update("MOCKUP_PROJECT" => project)
34
31
  end
35
-
32
+
36
33
  def run!
37
34
  target_path = self.target_path
38
- source_path = self.project.html_path
39
-
40
-
35
+ source_path = project.html_path
36
+
41
37
  filter = "**/*.html"
42
- raise ArgumentError, "Target #{target_path} already exists, please choose a new directory to extract into" if target_path.exist?
43
-
38
+ fail(
39
+ ArgumentError,
40
+ "Target #{target_path} already exists, please choose a new directory to extract into"
41
+ ) if target_path.exist?
42
+
44
43
  mkdir_p(target_path)
45
44
  target_path = target_path.realpath
46
-
45
+
47
46
  # Copy source to target first, we'll overwrite the templates later on.
48
47
  cp_r(source_path.children, target_path)
49
-
48
+
50
49
  Dir.chdir(source_path) do
51
50
  Dir.glob(filter).each do |file_path|
52
51
  self.run_on_file!(file_path, @options[:env])
53
52
  end
54
- end
53
+ end
55
54
  end
56
-
55
+
57
56
  def run_on_file!(file_path, env = {})
58
- source = self.extract_source_from_file(file_path, env)
59
- File.open(target_path + file_path,"w"){|f| f.write(source) }
57
+ source = extract_source_from_file(file_path, env)
58
+ File.open(target_path + file_path, "w") { |f| f.write(source) }
60
59
  end
61
-
60
+
62
61
  # Runs the extractor on a single file and return processed source.
63
62
  def extract_source_from_file(file_path, env = {})
64
- source = Roger::Template.open(file_path, :partials_path => self.project.partial_path, :layouts_path => self.project.layouts_path).render(env.dup)
63
+ source = Roger::Template.open(
64
+ file_path,
65
+ partials_path: project.partial_path,
66
+ layouts_path: project.layouts_path
67
+ ).render(env.dup)
68
+
69
+ source = relativize_urls(source, file_path) if @options[:url_relativize]
65
70
 
66
- if @options[:url_relativize]
67
- source = relativize_urls(source, file_path)
68
- end
69
-
70
71
  source
71
72
  end
72
-
73
-
73
+
74
74
  protected
75
-
75
+
76
76
  def relativize_urls(source, file_path)
77
77
  doc = Hpricot(source)
78
78
  @options[:url_attributes].each do |attribute|
79
- (doc/"*[@#{attribute}]").each do |tag|
79
+ (doc / "*[@#{attribute}]").each do |tag|
80
80
  converted_url = @resolver.url_to_relative_url(tag[attribute], file_path)
81
-
81
+
82
82
  case converted_url
83
83
  when String
84
84
  tag[attribute] = converted_url
@@ -87,9 +87,8 @@ module Roger
87
87
  end
88
88
  end
89
89
  end
90
-
91
- doc.to_original_html
90
+
91
+ doc.to_original_html
92
92
  end
93
-
94
93
  end
95
- end
94
+ end
@@ -1,35 +1,43 @@
1
- require 'thor'
2
- require 'thor/group'
1
+ require "thor"
2
+ require "thor/group"
3
3
 
4
4
  module Roger
5
+ # Generators namespace
5
6
  module Generators
6
-
7
+ # Base Generator class
7
8
  class Base < Cli::Command
8
9
  end
9
10
 
10
- def self.register(name, sub = nil)
11
- # Hack to not break old tasks
12
- if name.kind_of?(Class)
13
- sub = name
14
- name = sub.to_s.sub(/Generator$/, "").sub(/^.*Generators::/,"").downcase
15
- else
16
- raise ArgumentError, "Name must be a symbol" unless name.kind_of?(Symbol)
17
- end
18
-
19
- name = name.to_s
11
+ def self.register(name, klass = nil)
12
+ name, klass = generator_name(name, klass)
20
13
 
21
- raise ArgumentError, "Another generator has already claimed the name #{name.inspect}" if Cli::Generate.tasks.has_key?(name)
14
+ fail(
15
+ ArgumentError,
16
+ "Generator name '#{name.inspect}' already in use"
17
+ ) if Cli::Generate.tasks.key?(name)
22
18
 
23
- usage = "#{name} #{sub.arguments.map{ |arg| arg.banner }.join(" ")}"
24
- long_desc = sub.desc || "Run #{name} generator"
19
+ usage = "#{name} #{klass.arguments.map(&:banner).join(' ')}"
20
+ long_desc = klass.desc || "Run #{name} generator"
25
21
 
26
- Cli::Generate.register sub, name, usage, long_desc
27
- Cli::Generate.tasks[name].options = sub.class_options if sub.class_options
22
+ Cli::Generate.register klass, name, usage, long_desc
23
+ Cli::Generate.tasks[name].options = klass.class_options if klass.class_options
28
24
  end
29
25
 
26
+ def self.generator_name(name, klass)
27
+ # Hack to not break old tasks
28
+
29
+ if name.is_a?(Class)
30
+ klass = name
31
+ name = klass.to_s.sub(/Generator$/, "").sub(/^.*Generators::/, "").downcase
32
+ else
33
+ fail ArgumentError, "Name must be a symbol" unless name.is_a?(Symbol)
34
+ end
35
+
36
+ [name.to_s, klass]
37
+ end
30
38
  end
31
39
  end
32
40
 
33
41
  # Default generators
34
42
  require File.dirname(__FILE__) + "/generators/new"
35
- require File.dirname(__FILE__) + "/generators/generator"
43
+ require File.dirname(__FILE__) + "/generators/generator"
@@ -1,23 +1,20 @@
1
+ # The generator generator!
1
2
  class Roger::Generators::GeneratorGenerator < Roger::Generators::Base
2
-
3
3
  include Thor::Actions
4
-
4
+
5
5
  desc "Create your own generator for roger"
6
- argument :name, :type => :string, :required => true, :desc => "Name of the new generator"
7
- argument :path, :type => :string, :required => true, :desc => "Path to generate the new generator"
8
- # class_option :template, :type => :string, :aliases => ["-t"], :desc => "Template to use, can be a path or a git repository remote, uses built in minimal as default"
9
-
6
+ argument :name, type: :string, required: true, desc: "Name of the new generator"
7
+ argument :path, type: :string, required: true, desc: "Path to generate the new generator"
8
+
10
9
  def self.source_root
11
10
  File.dirname(__FILE__)
12
11
  end
13
12
 
14
13
  def create_lib_file
15
14
  destination = "#{path}/#{name}_generator.rb"
16
- template('templates/generator.tt', destination)
15
+ template("templates/generator.tt", destination)
17
16
  say "Add `require #{destination}` to your mockup file and run mockup generate #{name}."
18
17
  end
19
-
20
-
21
18
  end
22
19
 
23
- Roger::Generators.register Roger::Generators::GeneratorGenerator
20
+ Roger::Generators.register Roger::Generators::GeneratorGenerator
@@ -1,67 +1,82 @@
1
- require 'shellwords'
1
+ require "shellwords"
2
2
 
3
+ # Generator to create a new HTML mockup based on an existing skeleton
3
4
  class Roger::Generators::NewGenerator < Thor::Group
4
-
5
5
  include Thor::Actions
6
-
6
+
7
7
  desc "Create a new HTML mockup based on an existing skeleton"
8
- argument :path, :type => :string, :required => true, :desc => "Path to generate mockup into"
9
- class_option :template, :type => :string, :aliases => ["-t"], :desc => "Template to use, can be a path or a git repository remote, uses built in minimal as default"
10
-
8
+
9
+ argument :path, type: :string, required: true, desc: "Path to generate mockup into"
10
+
11
+ class_option(
12
+ :template,
13
+ type: :string,
14
+ aliases: ["-t"],
15
+ desc: "Template to use, can be a path or a git remote, uses built in minimal as default"
16
+ )
17
+
11
18
  attr_reader :source_paths
12
-
13
- def setup_variables
19
+
20
+ def setup_variables
14
21
  self.destination_root = path
15
-
22
+
16
23
  @source_paths = []
17
-
24
+
18
25
  # Stuff to rm -rf later
19
26
  @cleanup = []
20
27
  end
21
-
28
+
22
29
  def validate_path_is_empty
23
- if File.directory?(self.destination_root)
24
- say "Directory #{self.destination_root} already exists, please only use this to create new mockups"
25
- exit(1)
26
- end
30
+ return unless File.directory?(destination_root)
31
+
32
+ say "Directory #{destination_root} already exists, please only use this to create new mockups"
33
+ exit(1)
27
34
  end
28
-
35
+
29
36
  def validate_template_path
30
- if options[:template]
31
- template = options[:template]
32
- else
33
- template = File.dirname(__FILE__) + "/../../../examples/default_template"
34
- end
35
-
37
+ template = options[:template] || File.dirname(__FILE__) + "/../../../examples/default_template"
38
+
36
39
  if File.exist?(template)
37
40
  say "Taking template from #{template}"
38
41
  @source_paths << template
39
42
  else
40
- # Hack to create temp directory
41
- t = Tempfile.new("htmlmockup-generate-new")
42
- tmp_dir = Pathname.new(t.path)
43
- t.close
44
- t.unlink
45
-
46
- if run("git clone --depth=1 #{Shellwords.escape(template)} #{tmp_dir}")
47
- say "Cloned template from #{template}"
48
- run("rm -rf #{tmp_dir + ".git"}")
49
- @source_paths << tmp_dir.to_s
50
- @cleanup << tmp_dir.to_s
51
- else
52
- say "Template path #{template} doesn't seem to be a git remote or a local path"
53
- exit(1)
54
- end
43
+ say "Getting template from git remote #{template}"
44
+ @source_paths << git_clone_template(template)
55
45
  end
56
- rescue Exception => e
46
+ rescue StandardError => e
57
47
  puts e
58
48
  puts e.backtrace.join("\n")
59
49
  end
60
-
50
+
61
51
  def create_mockup
62
52
  directory(".", ".")
63
53
  end
64
-
54
+
55
+ protected
56
+
57
+ def git_clone_template(template)
58
+ tmp_dir = temp_directory
59
+
60
+ if run("git clone --depth=1 #{Shellwords.escape(template)} #{tmp_dir}")
61
+ say "Cloned template from #{template}"
62
+ run("rm -rf #{tmp_dir + '.git'}")
63
+ @cleanup << tmp_dir.to_s
64
+ else
65
+ say "Template path #{template} doesn't seem to be a git remote or a local path"
66
+ exit(1)
67
+ end
68
+
69
+ tmp_dir
70
+ end
71
+
72
+ def temp_directory
73
+ # Hack to create temp directory
74
+ t = Tempfile.new("htmlmockup-generate-new")
75
+ tmp_dir = Pathname.new(t.path)
76
+ t.close
77
+ t.unlink
78
+ tmp_dir
79
+ end
65
80
  end
66
81
 
67
- Roger::Generators.register Roger::Generators::NewGenerator
82
+ Roger::Generators.register Roger::Generators::NewGenerator
@@ -1,13 +1,13 @@
1
+ # The <%= name.capitalize %> generator
1
2
  class <%= name.capitalize %>Generator < Roger::Generators::Base
2
-
3
3
  include Thor::Actions
4
-
4
+
5
5
  desc "<%= name.capitalize %> generator helps you doing ... and ..."
6
- argument :path, :type => :string, :required => true, :desc => "Path to generate the new generator"
7
-
6
+ argument :path, type: :string, required: true, desc: "Path to generate the new generator"
7
+
8
8
  def create_stuff
9
9
  # your stuff
10
10
  end
11
11
  end
12
12
 
13
- Roger::Generators.register <%= name.capitalize %>Generator
13
+ Roger::Generators.register <%= name.capitalize %>Generator
@@ -1,28 +1,29 @@
1
1
  module Roger
2
2
  module Helpers
3
+ # Helper to include the get_callbable method
3
4
  module GetCallable
4
- # Makes callable into a object that responds to call.
5
+ # Makes callable into a object that responds to call.
5
6
  #
6
- # @param [#call, Symbol, Class] callable If callable already responds to #call will just return callable, a Symbol will be searched for in the scope parameter, a class will be instantiated (and checked if it will respond to #call)
7
+ # @param [#call, Symbol, Class] callable If callable already responds to #call will
8
+ # just return callable, a Symbol will be searched for in the scope parameter, a class
9
+ # will be instantiated (and checked if it will respond to #call)
7
10
  # @param [Hash] map, Mapping to match symbol to a callable
8
11
  def get_callable(callable, map)
9
12
  return callable if callable.respond_to?(:call)
10
-
11
- if callable.kind_of?(Symbol) && map.has_key?(callable)
12
- callable = map[callable]
13
- end
14
-
15
- if callable.kind_of?(Class)
16
- callable = callable.new
17
- end
18
-
13
+
14
+ callable = map[callable] if callable.is_a?(Symbol) && map.key?(callable)
15
+
16
+ callable = callable.new if callable.is_a?(Class)
17
+
19
18
  if callable.respond_to?(:call)
20
19
  callable
21
20
  else
22
- raise ArgumentError, "Could not resolve #{callable.inspect}. Callable must be an object that responds to #call or a symbol that resolve to such an object or a class with a #call instance method."
21
+ error_message = "Could not resolve #{callable.inspect}. Callable must"
22
+ error_message << "be an object that responds to #call or a symbol that resolve"
23
+ error_message << "to such an object or a class with a #call instance method."
24
+ fail ArgumentError, error_message
23
25
  end
24
-
25
26
  end
26
27
  end
27
28
  end
28
- end
29
+ end
@@ -1,30 +1,52 @@
1
1
  module Roger
2
2
  module Helpers
3
+ # Helper module for logging
3
4
  module Logging
5
+ GRAY = "\e[37m"
6
+ RED = "\e[31m"
7
+
4
8
  # Write out a log message
5
9
  def log(part, msg, verbose = false, &block)
6
- if !verbose || verbose && self.project.options[:verbose]
7
- self.project.shell.say "\033[37m#{part.class.to_s}\033[0m" + " : " + msg.to_s, nil, true
8
- end
9
- if block_given?
10
- begin
11
- self.project.shell.padding = self.project.shell.padding + 1
12
- yield
13
- ensure
14
- self.project.shell.padding = self.project.shell.padding - 1
15
- end
10
+ shell = project.shell
11
+
12
+ if !verbose || verbose && project.options[:verbose]
13
+ shell.say(
14
+ shell.set_color(part_string(part), GRAY) +
15
+ " : " +
16
+ msg
17
+ )
16
18
  end
19
+
20
+ log_block_indent(&block) if block_given?
17
21
  end
18
22
 
19
23
  def debug(part, msg, &block)
20
- self.log(part, msg, true, &block)
24
+ log(part, msg, true, &block)
21
25
  end
22
26
 
23
27
  # Write out a warning message
24
28
  def warn(part, msg)
25
- self.project.shell.say "\033[37m#{part.class.to_s}\033[0m" + " : " + "\033[31m#{msg.to_s}\033[0m", nil, true
29
+ shell = project.shell
30
+
31
+ shell.say(
32
+ shell.set_color(part_string(part), GRAY) +
33
+ " : " +
34
+ shell.set_color(msg, RED)
35
+ )
26
36
  end
27
37
 
38
+ protected
39
+
40
+ def part_string(part)
41
+ part.is_a?(String) ? part : part.class.to_s
42
+ end
43
+
44
+ def log_block_indent(&_block)
45
+ project.shell.padding = project.shell.padding + 1
46
+ yield
47
+ ensure
48
+ project.shell.padding = project.shell.padding - 1
49
+ end
28
50
  end
29
51
  end
30
- end
52
+ end