cog 0.2.2 → 0.3.0
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.
- data/BuiltIn.cogfile +96 -0
- data/bin/cog +30 -39
- data/built_in/generators/sort.rb +3 -0
- data/built_in/plugins/basic/Cogfile +6 -0
- data/built_in/plugins/basic/templates/basic/generator.rb.erb +1 -0
- data/built_in/templates/cog/Cogfile.erb +40 -0
- data/built_in/templates/cog/plugin/generator.rb.erb.erb +3 -0
- data/{templates/cog/custom_tool/tool.rb.erb → built_in/templates/cog/plugin/plugin.rb.erb} +4 -11
- data/{templates → built_in/templates}/warning.erb +0 -0
- data/lib/cog.rb +25 -11
- data/lib/cog/config.rb +112 -49
- data/lib/cog/config/{language_methods.rb → language_config.rb} +23 -27
- data/lib/cog/config/plugin_config.rb +31 -0
- data/lib/cog/config/project_config.rb +48 -0
- data/lib/cog/controllers.rb +6 -8
- data/lib/cog/controllers/generator_controller.rb +30 -21
- data/lib/cog/controllers/plugin_controller.rb +43 -0
- data/lib/cog/controllers/template_controller.rb +12 -33
- data/lib/cog/dsl.rb +9 -0
- data/lib/cog/dsl/cogfile.rb +145 -0
- data/lib/cog/dsl/language_dsl.rb +142 -0
- data/lib/cog/embed_context.rb +0 -2
- data/lib/cog/embeds.rb +2 -7
- data/lib/cog/errors.rb +11 -24
- data/lib/cog/generator.rb +10 -15
- data/lib/cog/generator/file_methods.rb +2 -2
- data/lib/cog/generator/filters.rb +10 -14
- data/lib/cog/generator/language_methods.rb +2 -3
- data/lib/cog/generator_sandbox.rb +32 -0
- data/lib/cog/helpers.rb +10 -2
- data/lib/cog/helpers/cascading_set.rb +104 -0
- data/lib/cog/{embeds → helpers}/file_scanner.rb +1 -1
- data/lib/cog/language.rb +140 -0
- data/lib/cog/native_extensions.rb +2 -0
- data/lib/cog/native_extensions/array.rb +19 -0
- data/lib/cog/native_extensions/string.rb +54 -0
- data/lib/cog/plugin.rb +35 -0
- data/lib/cog/spec_helpers.rb +36 -14
- data/lib/cog/spec_helpers/matchers.rb +14 -4
- data/lib/cog/spec_helpers/matchers/match_maker.rb +1 -1
- data/lib/cog/spec_helpers/runner.rb +3 -9
- data/lib/cog/version.rb +1 -1
- metadata +27 -44
- data/Default.cogfile +0 -25
- data/lib/cog/built_in_tools.rb +0 -9
- data/lib/cog/built_in_tools/basic.rb +0 -10
- data/lib/cog/built_in_tools/basic/cog_tool.rb +0 -11
- data/lib/cog/config/cogfile.rb +0 -117
- data/lib/cog/config/lang_info.rb +0 -40
- data/lib/cog/config/project_methods.rb +0 -35
- data/lib/cog/config/tool_methods.rb +0 -94
- data/lib/cog/controllers/tool_controller.rb +0 -50
- data/lib/cog/helpers/cascading_template_set.rb +0 -75
- data/lib/cog/helpers/string.rb +0 -26
- data/lib/cog/languages.rb +0 -52
- data/lib/cog/languages/c_language.rb +0 -29
- data/lib/cog/languages/c_plus_plus_language.rb +0 -28
- data/lib/cog/languages/c_sharp_language.rb +0 -24
- data/lib/cog/languages/java_language.rb +0 -24
- data/lib/cog/languages/java_script_language.rb +0 -24
- data/lib/cog/languages/language.rb +0 -73
- data/lib/cog/languages/mixins.rb +0 -10
- data/lib/cog/languages/mixins/c_style_comments.rb +0 -23
- data/lib/cog/languages/mixins/hash_comments.rb +0 -19
- data/lib/cog/languages/python_language.rb +0 -20
- data/lib/cog/languages/qt_project_language.rb +0 -16
- data/lib/cog/languages/ruby_language.rb +0 -28
- data/lib/cog/tool.rb +0 -61
- data/lib/cog/tool/dsl.rb +0 -26
- data/templates/basic/generator.rb.erb +0 -4
- data/templates/cog/custom_tool/Gemfile.erb +0 -8
- data/templates/cog/custom_tool/LICENSE.erb +0 -18
- data/templates/cog/custom_tool/README.markdown.erb +0 -18
- data/templates/cog/custom_tool/Rakefile.erb +0 -15
- data/templates/cog/custom_tool/cog_tool.rb.erb +0 -17
- data/templates/cog/custom_tool/generator.rb.erb.erb +0 -9
- data/templates/cog/custom_tool/template.txt.erb.erb +0 -1
- data/templates/cog/custom_tool/tool.gemspec.erb +0 -17
- data/templates/cog/custom_tool/version.rb.erb +0 -5
data/lib/cog/language.rb
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
module Cog
|
2
|
+
|
3
|
+
# Describes a language support by Cog
|
4
|
+
class Language
|
5
|
+
|
6
|
+
# @return [Array<String>] list of file extensions
|
7
|
+
attr_reader :extensions
|
8
|
+
|
9
|
+
# @return [String] unique lower case identifier
|
10
|
+
attr_reader :key
|
11
|
+
|
12
|
+
# @return [String] readable name for the language
|
13
|
+
attr_reader :name
|
14
|
+
|
15
|
+
# @return [String] the style of comments used by this language
|
16
|
+
attr_reader :comment_style
|
17
|
+
|
18
|
+
# @return [String] the style of include guards used by this language
|
19
|
+
attr_reader :include_guard_style
|
20
|
+
|
21
|
+
# @api developer
|
22
|
+
# Initialize with default values
|
23
|
+
# @param key [String] unique case-insensitive identifier
|
24
|
+
def initialize(key = :text)
|
25
|
+
@key = key.to_s.downcase
|
26
|
+
@name = key.to_s
|
27
|
+
@comment_pattern = '^\s*(%s)\s*$'
|
28
|
+
@comment_prefix = nil
|
29
|
+
@multiline_comment_prefix = nil
|
30
|
+
@multiline_comment_postfix = nil
|
31
|
+
@extensions = []
|
32
|
+
identibitch = lambda {|name| ''}
|
33
|
+
@use_named_scope_block = identibitch
|
34
|
+
@named_scope_begin_block = identibitch
|
35
|
+
@named_scope_end_block = identibitch
|
36
|
+
@include_guard_begin_block = identibitch
|
37
|
+
@include_guard_end_block = identibitch
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param nested_pattern [String] regular expression pattern (as a string) to embed in the regular expression which matches one line comments in this language
|
41
|
+
# @return [Regexp] pattern for matching one line comments in this language
|
42
|
+
def comment_pattern(nested_pattern)
|
43
|
+
Regexp.new(@comment_pattern % nested_pattern)
|
44
|
+
end
|
45
|
+
|
46
|
+
# @param text [String] some text which should be rendered as a comment
|
47
|
+
# @return [String] a comment appropriate for this language
|
48
|
+
def comment(text)
|
49
|
+
if text =~ /\n/
|
50
|
+
multi_line_comment text
|
51
|
+
else
|
52
|
+
one_line_comment text
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# @api developer
|
57
|
+
def one_line_comment(text)
|
58
|
+
if @comment_prefix
|
59
|
+
"#{@comment_prefix} #{text}"
|
60
|
+
elsif @multiline_comment_prefix
|
61
|
+
"#{@multiline_comment_prefix} #{text} #{@multiline_comment_postfix}"
|
62
|
+
else
|
63
|
+
text
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# @api developer
|
68
|
+
def multi_line_comment(text)
|
69
|
+
if @multiline_comment_prefix
|
70
|
+
"#{@multiline_comment_prefix}\n#{text}\n#{@multiline_comment_postfix}"
|
71
|
+
elsif @comment_prefix
|
72
|
+
text.split("\n").collect do |line|
|
73
|
+
"#{@comment_prefix} #{line}"
|
74
|
+
end.join("\n")
|
75
|
+
else
|
76
|
+
text
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# @api developer
|
81
|
+
# Called after all Cogfiles have been processed
|
82
|
+
# @param other [Language] language to borrow notation from
|
83
|
+
def apply_comment_style(other)
|
84
|
+
@comment_prefix = other.instance_eval {@comment_prefix}
|
85
|
+
@multiline_comment_prefix = other.instance_eval {@multiline_comment_prefix}
|
86
|
+
@multiline_comment_postfix = other.instance_eval {@multiline_comment_postfix}
|
87
|
+
@comment_pattern = other.instance_eval {@comment_pattern}
|
88
|
+
end
|
89
|
+
|
90
|
+
# @api developer
|
91
|
+
# Called after all Cogfiles have been processed
|
92
|
+
# @param other [Language] language to borrow notation from
|
93
|
+
def apply_include_guard_style(other)
|
94
|
+
@include_guard_begin_block = other.instance_eval {@include_guard_begin_block}
|
95
|
+
@include_guard_end_block = other.instance_eval {@include_guard_end_block}
|
96
|
+
end
|
97
|
+
|
98
|
+
# @param w [FixNum] width of the first column
|
99
|
+
# @return [String] one line summary in two columns
|
100
|
+
def to_s(w=nil)
|
101
|
+
w ||= @name.length
|
102
|
+
"#{@name.ljust w} -> #{@extensions.collect {|x| x.to_s}.sort.join ', '}"
|
103
|
+
end
|
104
|
+
|
105
|
+
# Sort by name
|
106
|
+
def <=>(other)
|
107
|
+
@name <=> other.name
|
108
|
+
end
|
109
|
+
|
110
|
+
# @param name [String] name of the scope to use
|
111
|
+
# @return [String] a using statement for the named scope
|
112
|
+
def use_named_scope(name)
|
113
|
+
@use_named_scope_block.call name
|
114
|
+
end
|
115
|
+
|
116
|
+
# @param name [String] name of the scope
|
117
|
+
# @return [String] begin a named scope
|
118
|
+
def named_scope_begin(name)
|
119
|
+
@named_scope_begin_block.call name
|
120
|
+
end
|
121
|
+
|
122
|
+
# @param name [String] name of the scope
|
123
|
+
# @return [String] end the given named scope
|
124
|
+
def named_scope_end(name)
|
125
|
+
@named_scope_end_block.call name
|
126
|
+
end
|
127
|
+
|
128
|
+
# @param name [String] name of the module to protect
|
129
|
+
# @return [String] an include guard statement
|
130
|
+
def include_guard_begin(name)
|
131
|
+
@include_guard_begin_block.call name
|
132
|
+
end
|
133
|
+
|
134
|
+
# @param name [String] name of the module to protect
|
135
|
+
# @return [String] an include guard end statement
|
136
|
+
def include_guard_end(name)
|
137
|
+
@include_guard_end_block.call name
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# @api developer
|
2
|
+
class Array
|
3
|
+
|
4
|
+
# Iterate through each path in this array
|
5
|
+
# @yieldparam source [String] readable label for the source. In the case of plugins, the plugin name
|
6
|
+
# @yieldparam source_type [Symbol] one of :built_in, :user, :plugin, or :project
|
7
|
+
# @yieldparam path [String] a path to a cog resource, such as a template or generator
|
8
|
+
# @return [Object] the return value of the block
|
9
|
+
def each_with_cog_source(&block)
|
10
|
+
each do |path|
|
11
|
+
source, source_type = if plugin = path.relative_to_which_plugin?
|
12
|
+
[plugin.name, :plugin]
|
13
|
+
else
|
14
|
+
path.cog_source_and_type
|
15
|
+
end
|
16
|
+
block.call source, source_type, path
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# @api developer
|
2
|
+
class String
|
3
|
+
|
4
|
+
# @return [String] strips {Cog::Config::ProjectConfig#project_root} from the beginning of this string
|
5
|
+
def relative_to_project_root
|
6
|
+
if Cog.show_fullpaths?
|
7
|
+
File.expand_path self
|
8
|
+
else
|
9
|
+
Cog.project? ? relative_to(Cog.project_root) : dup
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# @param prefix [String] path prefix to strip from the beginning of this string
|
14
|
+
# @return [String] this string as a file system path relative to the +prefix+
|
15
|
+
def relative_to(prefix)
|
16
|
+
if Cog.show_fullpaths?
|
17
|
+
File.expand_path self
|
18
|
+
else
|
19
|
+
prefix && start_with?(prefix.to_s) ? slice(prefix.to_s.length+1..-1) : dup
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [Cog::Plugin,nil] if this string can be interpretted as a path relative to one of the registered cog plugins, return that plugin, otherwise return +nil+
|
24
|
+
def relative_to_which_plugin?
|
25
|
+
Cog.plugins.each do |plugin|
|
26
|
+
return plugin if start_with?(plugin.path)
|
27
|
+
end
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
|
31
|
+
# @param ext [String] file extension to remove from the end of this string
|
32
|
+
# @return [String] a copy of this string with the given extension removed. Does nothing if this string does not edit with the extension
|
33
|
+
def without_extension(ext)
|
34
|
+
return dup if ext.nil?
|
35
|
+
ext = ext.to_s
|
36
|
+
ext = '.' + ext unless ext.start_with? '.'
|
37
|
+
end_with?(ext) ? slice(0..(-ext.length - 1)) : dup
|
38
|
+
end
|
39
|
+
|
40
|
+
# @return [String, String] source and type, where type is one of <tt>:project</tt>, <tt>:user</tt>, <tt>:built_in</tt>, <tt>:gem</tt>, or <tt>:unknown</tt>
|
41
|
+
def cog_source_and_type
|
42
|
+
if start_with?(Cog.project_root) || start_with?(Cog.project_template_path) || start_with?(Cog.project_generator_path) || start_with?(Cog.project_plugin_path)
|
43
|
+
[File.basename(Cog.project_root), :project]
|
44
|
+
elsif start_with? Cog.user_dir
|
45
|
+
[File.basename(ENV['HOME']), :user]
|
46
|
+
elsif start_with? Cog.gem_dir
|
47
|
+
['cog', :built_in]
|
48
|
+
elsif start_with? File.expand_path(File.join(Cog.gem_dir, '..'))
|
49
|
+
['gem', :gem]
|
50
|
+
else
|
51
|
+
['unknown', :unknown]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/cog/plugin.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
module Cog
|
2
|
+
|
3
|
+
# Describes a plugin found on the {Config#plugin_path}. The plugin {DSL::Cogfile} will have already been processed, and should have contained a call to {DSL::Cogfile#autoload_plugin}, which will make it's DSL available to generators via a {GeneratorSandbox}.
|
4
|
+
class Plugin
|
5
|
+
|
6
|
+
# @return [String] name of the plugin
|
7
|
+
attr_reader :name
|
8
|
+
|
9
|
+
# @return [String] path to the plugin directory
|
10
|
+
attr_reader :path
|
11
|
+
|
12
|
+
# @return [String] path to the plugin's cogfile
|
13
|
+
attr_reader :cogfile_path
|
14
|
+
|
15
|
+
# @return [Block] the block to use to stamp the generator
|
16
|
+
attr_accessor :stamp_generator_block
|
17
|
+
|
18
|
+
# @param cogfile_path [String] path to the plugin Cogfile
|
19
|
+
def initialize(cogfile_path)
|
20
|
+
unless File.exists?(cogfile_path)
|
21
|
+
raise Errors::InvalidPluginConfiguration.new(cogfile_path)
|
22
|
+
end
|
23
|
+
@cogfile_path = File.expand_path cogfile_path
|
24
|
+
@path = File.dirname @cogfile_path
|
25
|
+
@name = File.basename @path
|
26
|
+
@name = $1 if /^(.+?)\-(\d|\.)+(rc2)?$/ =~ @name
|
27
|
+
end
|
28
|
+
|
29
|
+
# Sort plugins by name
|
30
|
+
def <=>(other)
|
31
|
+
@name <=> other.name
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
data/lib/cog/spec_helpers.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'cog/spec_helpers/runner'
|
2
2
|
require 'cog/spec_helpers/matchers'
|
3
|
-
require 'fileutils'
|
4
3
|
|
5
4
|
module Cog
|
6
5
|
|
@@ -44,10 +43,15 @@ module Cog
|
|
44
43
|
File.expand_path File.join(File.dirname(__FILE__), '..', '..', 'spec')
|
45
44
|
end
|
46
45
|
|
47
|
-
# @return [String] directory of
|
46
|
+
# @return [String] directory of the active fixture.
|
48
47
|
def active_fixture_dir
|
49
48
|
File.join spec_root, 'active_fixture'
|
50
49
|
end
|
50
|
+
|
51
|
+
# @return [String] directory of the active home fixture.
|
52
|
+
def active_home_fixture_dir
|
53
|
+
File.join spec_root, 'active_home_fixture'
|
54
|
+
end
|
51
55
|
|
52
56
|
# @return [String] path to the Cogfile in the active spec fixture
|
53
57
|
def cogfile_path
|
@@ -68,15 +72,15 @@ module Cog
|
|
68
72
|
# @param name [String] template identifier (without the .erb extension)
|
69
73
|
# @return [String] absolute file system path to the template
|
70
74
|
def template(name)
|
71
|
-
File.expand_path File.join(active_fixture_dir, 'cog', 'templates',
|
75
|
+
File.expand_path File.join(active_fixture_dir, 'cog', 'templates', name.to_s)
|
72
76
|
end
|
73
77
|
|
74
|
-
# @param name [String]
|
75
|
-
# @return [String]
|
76
|
-
def
|
77
|
-
File.expand_path File.join(
|
78
|
+
# @param name [String] plugin name
|
79
|
+
# @return [String] absolute file system path to the plugin directory
|
80
|
+
def plugin(name)
|
81
|
+
File.expand_path File.join(active_fixture_dir, 'cog', 'plugins', name.to_s)
|
78
82
|
end
|
79
|
-
|
83
|
+
|
80
84
|
# @param filename [String] name of a generated source file
|
81
85
|
# @return [String] absolute path to the generated file
|
82
86
|
def generated_file(filename)
|
@@ -89,16 +93,34 @@ module Cog
|
|
89
93
|
# @return [nil]
|
90
94
|
def use_fixture(name)
|
91
95
|
path = File.join spec_root, 'fixtures', name.to_s
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
+
copy_fixture path, active_fixture_dir
|
97
|
+
Dir.chdir active_fixture_dir
|
98
|
+
nil
|
99
|
+
end
|
100
|
+
|
101
|
+
# The next cog spec will execute in a fresh copy of the given home fixture
|
102
|
+
# Home fixture directories are stored in <tt>spec/home_fixtures</tt>
|
103
|
+
# @param name [String] name of the home fixture
|
104
|
+
# @return [nil]
|
105
|
+
def use_home_fixture(name)
|
106
|
+
path = File.join spec_root, 'home_fixtures', name.to_s
|
107
|
+
copy_fixture path, active_home_fixture_dir
|
108
|
+
nil
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
def copy_fixture(source, dest)
|
114
|
+
if File.exists?(source) && File.directory?(source)
|
115
|
+
FileUtils.rm_rf dest if File.exists? dest
|
116
|
+
FileUtils.cp_r source, dest
|
96
117
|
else
|
97
118
|
throw :invalid_fixture_name
|
98
119
|
end
|
99
|
-
nil
|
100
120
|
end
|
101
121
|
|
122
|
+
public
|
123
|
+
|
124
|
+
extend self
|
102
125
|
end
|
103
|
-
|
104
126
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require 'cog/spec_helpers/matchers/match_maker'
|
2
1
|
require 'rspec'
|
2
|
+
require 'cog/spec_helpers/matchers/match_maker'
|
3
3
|
|
4
4
|
module Cog
|
5
5
|
module SpecHelpers
|
@@ -42,13 +42,23 @@ module Cog
|
|
42
42
|
end
|
43
43
|
|
44
44
|
# The target {Invocation} should write the given list of lines to standard output
|
45
|
-
# @param x [Array<String
|
45
|
+
# @param x [Array<String>, Regexp] a list of lines to match against standard output
|
46
46
|
# @return [nil]
|
47
47
|
def output(x)
|
48
48
|
match_maker do
|
49
|
-
message
|
49
|
+
message do
|
50
|
+
if x.is_a? Regexp
|
51
|
+
"to [write|not write] #{x.inspect} to STDOUT"
|
52
|
+
else
|
53
|
+
"to [write|not write] #{x.join "\n"} to STDOUT"
|
54
|
+
end
|
55
|
+
end
|
50
56
|
test do
|
51
|
-
|
57
|
+
if x.is_a? Regexp
|
58
|
+
x =~ lines.join("\n")
|
59
|
+
else
|
60
|
+
lines.zip(x).all? {|a, b| a.strip == b.to_s.strip}
|
61
|
+
end
|
52
62
|
end
|
53
63
|
end
|
54
64
|
end
|
@@ -6,13 +6,9 @@ module Cog
|
|
6
6
|
# Points to the +cog+ command-line app
|
7
7
|
class Runner
|
8
8
|
|
9
|
-
# Value of the COG_TOOLS environment variable for invocations returned from #run
|
10
|
-
attr_accessor :tools
|
11
|
-
|
12
9
|
# @param path_to_cl_app [String] path
|
13
10
|
def initialize
|
14
11
|
@cog = File.expand_path File.join(File.dirname(__FILE__), '..', '..', '..', 'bin', 'cog')
|
15
|
-
@tools = []
|
16
12
|
end
|
17
13
|
|
18
14
|
# Run cog with the given arguments
|
@@ -20,7 +16,7 @@ module Cog
|
|
20
16
|
# @return [Invocation] an object which can be used with custom {Matchers}
|
21
17
|
def run(*args)
|
22
18
|
args = [@cog, '--colorless'] + args
|
23
|
-
Invocation.new(args.collect {|x| x.to_s}
|
19
|
+
Invocation.new(args.collect {|x| x.to_s})
|
24
20
|
end
|
25
21
|
end
|
26
22
|
|
@@ -31,10 +27,8 @@ module Cog
|
|
31
27
|
|
32
28
|
# @api developer
|
33
29
|
# @param cmd [Array<String>] path to +cog+ executable and arguments
|
34
|
-
# @option opt [Array<String>] :tools ([]) a list of tools to add to the +COG_TOOLS+ environment variable just before running the command with {#exec}
|
35
30
|
def initialize(cmd, opt={})
|
36
31
|
@cmd = cmd
|
37
|
-
@tools = (opt[:tools] || []).join ':'
|
38
32
|
end
|
39
33
|
|
40
34
|
# Execute the command
|
@@ -43,7 +37,7 @@ module Cog
|
|
43
37
|
# @return [nil]
|
44
38
|
def exec(&block)
|
45
39
|
@cmd = ['bundle', 'exec'] + @cmd
|
46
|
-
ENV['
|
40
|
+
ENV['HOME'] = SpecHelpers.active_home_fixture_dir
|
47
41
|
Open3.popen3 *@cmd do |i,o,e,t|
|
48
42
|
block.call i,o,e
|
49
43
|
end
|
@@ -52,7 +46,7 @@ module Cog
|
|
52
46
|
# @api developer
|
53
47
|
# @return [String] loggable representation
|
54
48
|
def to_s
|
55
|
-
"
|
49
|
+
"`#{@cmd.compact.join ' '}`"
|
56
50
|
end
|
57
51
|
end
|
58
52
|
|
data/lib/cog/version.rb
CHANGED