roger 1.1.3 → 1.2.1

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