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.
- checksums.yaml +4 -4
- data/.hound.yml +2 -0
- data/.rubocop.yml +47 -0
- data/.travis.yml +1 -5
- data/CHANGELOG.md +8 -0
- data/Gemfile +3 -3
- data/Rakefile +10 -4
- data/bin/roger +1 -1
- data/doc/mockupfile.md +97 -0
- data/doc/templating.md +5 -1
- data/examples/default_template/Gemfile +1 -1
- data/lib/roger/cli.rb +41 -36
- data/lib/roger/cli/command.rb +2 -4
- data/lib/roger/cli/generate.rb +1 -0
- data/lib/roger/cli/release.rb +2 -2
- data/lib/roger/cli/serve.rb +11 -11
- data/lib/roger/cli/test.rb +6 -5
- data/lib/roger/extractor.rb +42 -43
- data/lib/roger/generators.rb +27 -19
- data/lib/roger/generators/generator.rb +7 -10
- data/lib/roger/generators/new.rb +56 -41
- data/lib/roger/generators/templates/generator.tt +5 -5
- data/lib/roger/helpers/get_callable.rb +15 -14
- data/lib/roger/helpers/logging.rb +35 -13
- data/lib/roger/mockupfile.rb +13 -23
- data/lib/roger/project.rb +41 -34
- data/lib/roger/rack/roger.rb +28 -29
- data/lib/roger/rack/sleep.rb +4 -5
- data/lib/roger/release.rb +95 -72
- data/lib/roger/release/cleaner.rb +14 -13
- data/lib/roger/release/finalizers.rb +10 -10
- data/lib/roger/release/finalizers/dir.rb +17 -19
- data/lib/roger/release/finalizers/git_branch.rb +76 -38
- data/lib/roger/release/finalizers/rsync.rb +60 -49
- data/lib/roger/release/finalizers/zip.rb +32 -29
- data/lib/roger/release/injector.rb +43 -37
- data/lib/roger/release/processors.rb +24 -22
- data/lib/roger/release/processors/mockup.rb +97 -69
- data/lib/roger/release/processors/url_relativizer.rb +57 -30
- data/lib/roger/release/scm.rb +30 -27
- data/lib/roger/release/scm/git.rb +101 -92
- data/lib/roger/resolver.rb +86 -61
- data/lib/roger/server.rb +52 -27
- data/lib/roger/template.rb +102 -74
- data/lib/roger/test.rb +16 -13
- data/lib/roger/version.rb +3 -2
- data/roger.gemspec +9 -5
- data/test/helpers/cli.rb +17 -15
- data/test/project/Gemfile +2 -2
- data/test/project/html/formats/csv.rcsv +0 -0
- data/test/project/lib/generators/test.rb +2 -3
- data/test/project/lib/tests/fail/fail.rb +5 -6
- data/test/project/lib/tests/noop/lib/cli.rb +2 -1
- data/test/project/lib/tests/noop/lib/test.rb +5 -5
- data/test/project/lib/tests/noop/noop.rb +2 -1
- data/test/project/lib/tests/succeed/succeed.rb +5 -6
- data/test/unit/cli/cli_base_test.rb +2 -3
- data/test/unit/cli/cli_generate_test.rb +9 -10
- data/test/unit/cli/cli_serve_test.rb +22 -18
- data/test/unit/cli/cli_test_test.rb +13 -15
- data/test/unit/cli/cli_version_test.rb +4 -4
- data/test/unit/generators_test.rb +8 -10
- data/test/unit/helpers/logging_test.rb +64 -0
- data/test/unit/rack/roger_test.rb +21 -0
- data/test/unit/release/cleaner_test.rb +23 -19
- data/test/unit/release/finalizers/git_branch_test.rb +2 -1
- data/test/unit/release/finalizers/zip_test.rb +48 -0
- data/test/unit/release/mockup_test.rb +48 -0
- data/test/unit/release/processors_test.rb +19 -19
- data/test/unit/release_test.rb +15 -14
- data/test/unit/resolver_test.rb +21 -14
- data/test/unit/server_test.rb +31 -0
- data/test/unit/template_test.rb +58 -36
- data/test/unit/test_test.rb +3 -2
- metadata +35 -9
- data/test/Mockupfile-syntax.rb +0 -93
data/lib/roger/cli/test.rb
CHANGED
@@ -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
|
-
|
12
|
-
|
13
|
-
|
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
|
data/lib/roger/extractor.rb
CHANGED
@@ -1,84 +1,84 @@
|
|
1
|
-
require
|
2
|
-
require File.dirname(__FILE__) +
|
1
|
+
require "hpricot"
|
2
|
+
require File.dirname(__FILE__) + "/resolver"
|
3
3
|
|
4
4
|
module Roger
|
5
|
-
|
6
|
-
#
|
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
|
-
:
|
27
|
-
:
|
28
|
-
:
|
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 =
|
39
|
-
|
40
|
-
|
35
|
+
source_path = project.html_path
|
36
|
+
|
41
37
|
filter = "**/*.html"
|
42
|
-
|
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 =
|
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(
|
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
|
data/lib/roger/generators.rb
CHANGED
@@ -1,35 +1,43 @@
|
|
1
|
-
require
|
2
|
-
require
|
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,
|
11
|
-
|
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
|
-
|
14
|
+
fail(
|
15
|
+
ArgumentError,
|
16
|
+
"Generator name '#{name.inspect}' already in use"
|
17
|
+
) if Cli::Generate.tasks.key?(name)
|
22
18
|
|
23
|
-
usage = "#{name} #{
|
24
|
-
long_desc =
|
19
|
+
usage = "#{name} #{klass.arguments.map(&:banner).join(' ')}"
|
20
|
+
long_desc = klass.desc || "Run #{name} generator"
|
25
21
|
|
26
|
-
Cli::Generate.register
|
27
|
-
Cli::Generate.tasks[name].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, :
|
7
|
-
argument :path, :
|
8
|
-
|
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(
|
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
|
data/lib/roger/generators/new.rb
CHANGED
@@ -1,67 +1,82 @@
|
|
1
|
-
require
|
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
|
-
|
9
|
-
|
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
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|
-
|
31
|
-
|
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
|
-
|
41
|
-
|
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
|
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, :
|
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
|
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.
|
12
|
-
|
13
|
-
|
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
|
-
|
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
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
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
|
-
|
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
|