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