cog 0.0.19 → 0.0.20
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/lib/cog.rb +5 -2
- data/lib/cog/config.rb +26 -20
- data/lib/cog/config/cogfile.rb +21 -20
- data/lib/cog/generator.rb +51 -60
- data/lib/cog/helpers.rb +1 -0
- data/lib/cog/helpers/string.rb +11 -0
- data/lib/cog/spec_helpers.rb +41 -11
- data/lib/cog/spec_helpers/matchers.rb +14 -7
- data/lib/cog/spec_helpers/matchers/match_maker.rb +39 -17
- data/lib/cog/spec_helpers/runner.rb +18 -10
- data/lib/cog/tool.rb +7 -7
- data/lib/cog/version.rb +3 -1
- data/templates/{cog/snippets/c++/generated_warning.h.erb → warning.h.erb} +0 -0
- data/yard-templates/default/fulldoc/html/css/common.css +6 -0
- metadata +13 -16
- data/API.rdoc +0 -6
- data/templates/cog/snippets/generated_warning.txt +0 -7
data/lib/cog.rb
CHANGED
@@ -4,11 +4,13 @@ require 'cog/tool'
|
|
4
4
|
require 'cog/version'
|
5
5
|
require 'fileutils'
|
6
6
|
|
7
|
-
#
|
8
|
-
# the
|
7
|
+
# +cog+ is a command line utility that makes it a bit easier to organize a project
|
8
|
+
# which uses code generation. These are the API docs, but you might want to read
|
9
|
+
# the {https://github.com/ktonon/cog#readme general introduction} first.
|
9
10
|
module Cog
|
10
11
|
|
11
12
|
# Prepare the project in the present working directory for use with +cog+
|
13
|
+
# @return [nil]
|
12
14
|
def self.initialize_project
|
13
15
|
Object.new.instance_eval do
|
14
16
|
class << self ; include Generator ; end
|
@@ -16,6 +18,7 @@ module Cog
|
|
16
18
|
config = Config.instance
|
17
19
|
touch_path config.project_generators_path
|
18
20
|
touch_path config.project_templates_path
|
21
|
+
nil
|
19
22
|
end
|
20
23
|
end
|
21
24
|
|
data/lib/cog/config.rb
CHANGED
@@ -3,50 +3,57 @@ require 'singleton'
|
|
3
3
|
|
4
4
|
module Cog
|
5
5
|
|
6
|
-
# This is a low level interface. It is mainly used by the Generator methods
|
6
|
+
# This is a low level interface. It is mainly used by the {Generator} methods
|
7
7
|
# to determine where to find things, and where to put them. When +cog+ is used
|
8
|
-
# in a project the values of the singleton Config
|
9
|
-
# a Cogfile.
|
8
|
+
# in a project the values of the singleton {Config.instance} should be configured using
|
9
|
+
# a {Cogfile}.
|
10
10
|
class Config
|
11
11
|
|
12
|
-
#
|
12
|
+
# @return [String] path to the project's {Cogfile}
|
13
13
|
attr_reader :cogfile_path
|
14
14
|
|
15
|
-
#
|
15
|
+
# @return [String] default language in which to generated application source code
|
16
16
|
attr_reader :language
|
17
17
|
|
18
|
-
#
|
18
|
+
# @return [String] directory in which to find project generators
|
19
19
|
attr_reader :project_generators_path
|
20
20
|
|
21
|
-
#
|
21
|
+
# @return [String] directory in which the project's {Cogfile} is found
|
22
22
|
attr_reader :project_root
|
23
23
|
|
24
|
-
#
|
24
|
+
# @return [String] directory to which project source code is generated
|
25
25
|
attr_reader :project_source_path
|
26
26
|
|
27
|
-
#
|
27
|
+
# @return [String] directory in which to find custom project templates
|
28
28
|
attr_reader :project_templates_path
|
29
29
|
|
30
|
-
#
|
31
|
-
# That is, could a Cogfile be found?
|
30
|
+
# @return [Boolean] are we operating in the context of a project?
|
32
31
|
def project?
|
33
32
|
!@project_root.nil?
|
34
33
|
end
|
35
34
|
|
36
|
-
#
|
35
|
+
# @param value [String] a value which is set by the active tool
|
37
36
|
attr_writer :tool_templates_path
|
38
37
|
|
39
|
-
#
|
38
|
+
# @return [String] a value which is set by the active tool
|
40
39
|
attr_accessor :tool_generator_template
|
41
40
|
|
42
|
-
# A list of directories in which to find ERB template files
|
43
|
-
#
|
41
|
+
# A list of directories in which to find ERB template files
|
42
|
+
#
|
43
|
+
# Templates should be looked for in the following order as determined by the list returned from this method
|
44
|
+
#
|
45
|
+
# * {#project_templates_path}, present if we are in the context of a {#project?}
|
46
|
+
# * tool templates, present if we are in the context of a tool (i.e. a tool has set {#tool_templates_path=})
|
47
|
+
# * +cog+ built-in templates, always present
|
48
|
+
#
|
49
|
+
# @return [Array<String>] a list of directories order with ascending priority
|
44
50
|
def template_paths
|
45
51
|
[@project_templates_path, @tool_templates_path, File.join(Config.gem_dir, 'templates')].compact
|
46
52
|
end
|
47
53
|
|
48
54
|
# Location of the installed cog gem
|
49
|
-
|
55
|
+
# @return [String] path to the cog gem
|
56
|
+
def self.gem_dir
|
50
57
|
spec = Gem.loaded_specs['cog']
|
51
58
|
if spec.nil?
|
52
59
|
# The current __FILE__ is:
|
@@ -57,18 +64,17 @@ module Cog
|
|
57
64
|
end
|
58
65
|
end
|
59
66
|
|
60
|
-
# The singleton instance
|
67
|
+
# The singleton instance
|
61
68
|
#
|
62
69
|
# Initialized using the Cogfile for the current project, if any can be
|
63
|
-
# found. If not, then #project? will be +false+ and all the +project_...+
|
70
|
+
# found. If not, then {#project?} will be +false+ and all the +project_...+
|
64
71
|
# attributes will be +nil+.
|
65
72
|
#
|
66
73
|
# The Cogfile will be looked for in the present working directory. If none
|
67
74
|
# is found there the parent directory will be checked, and then the
|
68
75
|
# grandparent, and so on.
|
69
76
|
#
|
70
|
-
#
|
71
|
-
# An instance of Config.
|
77
|
+
# @return [Config] the singleton Config instance
|
72
78
|
def self.instance
|
73
79
|
return @instance if @instance
|
74
80
|
@instance = self.new
|
data/lib/cog/config/cogfile.rb
CHANGED
@@ -3,32 +3,35 @@ module Cog
|
|
3
3
|
|
4
4
|
# In your project's +Cogfile+, +self+ has been set to an instance of this class.
|
5
5
|
#
|
6
|
-
#
|
6
|
+
# Typing <tt>cog init</tt> will create a +Cogfile+ in the present working directory.
|
7
|
+
# +Cogfile+ files are used to configure an instance of {Config}.
|
8
|
+
#
|
9
|
+
# @example
|
7
10
|
# project_generators_path 'cog/generators'
|
8
11
|
# project_templates_path 'cog/templates'
|
9
12
|
# project_source_path 'src'
|
10
13
|
# language 'c++'
|
11
14
|
#
|
12
|
-
# Typing `cog init` will create a +Cogfile+ in the present working directory.
|
13
|
-
#
|
14
|
-
# +Cogfile+ files are used to configure an instance of Config.
|
15
15
|
class Cogfile
|
16
|
-
|
17
|
-
|
16
|
+
|
17
|
+
# Initialize with an instance of {Config}
|
18
|
+
# @api developer
|
19
|
+
# @param config [Config] the object which will be configured by this Cogfile
|
20
|
+
def initialize(config)
|
18
21
|
@config = config
|
19
22
|
end
|
20
23
|
|
21
|
-
# Interpret the Cogfile
|
22
|
-
|
24
|
+
# Interpret the +Cogfile+ at {Config#cogfile_path}
|
25
|
+
# @api developer
|
26
|
+
def interpret
|
23
27
|
eval File.read(@config.cogfile_path), binding
|
24
28
|
rescue Exception => e
|
25
29
|
raise CogfileError.new(e.to_s)
|
26
30
|
end
|
27
31
|
|
28
32
|
# Define the directory in which to find project generators
|
29
|
-
#
|
30
|
-
#
|
31
|
-
# * +absolute+ - If false, the path is relative to the directory containing the +Cogfile+
|
33
|
+
# @param path [String] a file system path
|
34
|
+
# @param absolute [Boolean] if +false+, the path is relative to {Config#project_root}
|
32
35
|
def project_generators_path(path, absolute=false)
|
33
36
|
@config.instance_eval do
|
34
37
|
@project_generators_path = absolute ? path : File.join(project_root, path)
|
@@ -36,9 +39,8 @@ module Cog
|
|
36
39
|
end
|
37
40
|
|
38
41
|
# Define the directory in which to find custom project templates
|
39
|
-
#
|
40
|
-
#
|
41
|
-
# * +absolute+ - If false, the path is relative to the directory containing the +Cogfile+
|
42
|
+
# @param path [String] a file system path
|
43
|
+
# @param absolute [Boolean] if +false+, the path is relative to {Config#project_root}
|
42
44
|
def project_templates_path(path, absolute=false)
|
43
45
|
@config.instance_eval do
|
44
46
|
@project_templates_path = absolute ? path : File.join(project_root, path)
|
@@ -46,9 +48,8 @@ module Cog
|
|
46
48
|
end
|
47
49
|
|
48
50
|
# Define the directory to which project source code is generated
|
49
|
-
#
|
50
|
-
#
|
51
|
-
# * +absolute+ - If false, the path is relative to the directory containing the +Cogfile+
|
51
|
+
# @param path [String] a file system path
|
52
|
+
# @param absolute [Boolean] if +false+, the path is relative to {Config#project_root}
|
52
53
|
def project_source_path(path, absolute=false)
|
53
54
|
@config.instance_eval do
|
54
55
|
@project_source_path = absolute ? path : File.join(project_root, path)
|
@@ -56,8 +57,7 @@ module Cog
|
|
56
57
|
end
|
57
58
|
|
58
59
|
# Define the default language in which to generated application source code
|
59
|
-
#
|
60
|
-
# * +lang+ - A code for the language. Acceptable values are <tt>c++</tt>.
|
60
|
+
# @param lang [String] a code for the language. Acceptable values are <tt>c++</tt>
|
61
61
|
def language(lang)
|
62
62
|
@config.instance_eval do
|
63
63
|
@language = lang
|
@@ -65,7 +65,8 @@ module Cog
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
-
# For wrapping errors which occur during the processing of a
|
68
|
+
# For wrapping errors which occur during the processing of a {Cogfile}
|
69
|
+
# @api client
|
69
70
|
class CogfileError < StandardError
|
70
71
|
def message
|
71
72
|
"in Cogfile, " + super
|
data/lib/cog/generator.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'cog/config'
|
2
2
|
require 'cog/errors'
|
3
|
+
require 'cog/helpers'
|
3
4
|
require 'erb'
|
4
5
|
require 'rainbow'
|
5
6
|
|
@@ -7,12 +8,14 @@ module Cog
|
|
7
8
|
|
8
9
|
# This module defines an interface which can be used by generator objects.
|
9
10
|
# Specifically, it makes it easy to find ERB templates and render them into
|
10
|
-
# generated source code files, using the #stamp method.
|
11
|
+
# generated source code files, using the {#stamp} method.
|
11
12
|
#
|
12
|
-
#
|
13
|
+
# @see https://github.com/ktonon/cog#generators Introduction to Generators
|
13
14
|
module Generator
|
14
15
|
|
15
|
-
#
|
16
|
+
# List the available project generators
|
17
|
+
# @param verbose [Boolean] should full generator paths be listed?
|
18
|
+
# @return [Array<String>] a list of generator names
|
16
19
|
def self.list(verbose=false)
|
17
20
|
if Config.instance.project?
|
18
21
|
x = Dir.glob(File.join Config.instance.project_generators_path, '*.rb')
|
@@ -23,15 +26,9 @@ module Cog
|
|
23
26
|
end
|
24
27
|
|
25
28
|
# Create a new generator
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
# ==== Options
|
31
|
-
# * +tool+ - the name of the tool to use (default: basic)
|
32
|
-
#
|
33
|
-
# ==== Returns
|
34
|
-
# Whether or not the generator was created successfully
|
29
|
+
# @param name [String] the name to use for the new generator
|
30
|
+
# @option opt [String] :tool ('basic') the name of the tool to use
|
31
|
+
# @return [Boolean] was the generator successfully created?
|
35
32
|
def self.create(name, opt={})
|
36
33
|
return false unless Config.instance.project?
|
37
34
|
|
@@ -72,12 +69,9 @@ module Cog
|
|
72
69
|
end
|
73
70
|
|
74
71
|
# Run the generator with the given name
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
# ==== Returns
|
80
|
-
# Whether or not the generator could be found
|
72
|
+
# @param name [String] name of the generator as returned by {Generator.list}
|
73
|
+
# @option opt [Boolean] :verbose (false) in the case of an exception, should a full stack trace be written?
|
74
|
+
# @return [Boolean] was the generator run successfully?
|
81
75
|
def self.run(name, opt={})
|
82
76
|
filename = File.join Cog::Config.instance.project_generators_path, "#{name}.rb"
|
83
77
|
if File.exists? filename
|
@@ -92,17 +86,10 @@ module Cog
|
|
92
86
|
false
|
93
87
|
end
|
94
88
|
|
95
|
-
# Get the template with the given name
|
96
|
-
#
|
97
|
-
#
|
98
|
-
#
|
99
|
-
# one of the template directories
|
100
|
-
#
|
101
|
-
# ==== Options
|
102
|
-
# * <tt>:absolute</tt> - is the +path+ argument absolute? (default: +false+)
|
103
|
-
#
|
104
|
-
# ==== Returns
|
105
|
-
# An instance of ERB.
|
89
|
+
# Get the template with the given name
|
90
|
+
# @param path [String] path to template file relative one of the {Config#template_paths}
|
91
|
+
# @option opt [Boolean] :absolute (false) is the +path+ argument absolute?
|
92
|
+
# @return [ERB] an instance of {http://ruby-doc.org/stdlib-1.9.3/libdoc/erb/rdoc/ERB.html ERB}
|
106
93
|
def get_template(path, opt={})
|
107
94
|
path += '.erb'
|
108
95
|
fullpath = if opt[:absolute]
|
@@ -117,19 +104,18 @@ module Cog
|
|
117
104
|
ERB.new File.read(fullpath), 0, '>'
|
118
105
|
end
|
119
106
|
|
120
|
-
# Stamp a template
|
121
|
-
#
|
122
|
-
#
|
123
|
-
#
|
124
|
-
#
|
125
|
-
#
|
126
|
-
#
|
127
|
-
|
128
|
-
# * <tt>:absolute_template_path</tt> - is the +template_path+ argument absolute? (default: +false+)
|
129
|
-
# * <tt>:absolute_destination</tt> - is the +destination+ argument absolute? (default: +false+)
|
130
|
-
def stamp(template_path, destination, opt={})
|
107
|
+
# Stamp a template into a file or return it as a string
|
108
|
+
# @param template_path [String] path to template file relative one of the {Config#template_paths}
|
109
|
+
# @param destination [String] path to which the generated file should be written, relative to the {Config#project_source_path}
|
110
|
+
# @option opt [Boolean] :absolute_template_path (false) is the +template_path+ absolute?
|
111
|
+
# @option opt [Boolean] :absolute_destination (false) is the +destination+ absolute?
|
112
|
+
# @option opt [Boolean] :quiet (false) suppress writing to STDOUT?
|
113
|
+
# @return [nil or String] if +destination+ is not provided, the stamped template is returned as a string
|
114
|
+
def stamp(template_path, destination=nil, opt={})
|
131
115
|
t = get_template template_path, :absolute => opt[:absolute_template_path]
|
132
116
|
b = opt[:binding] || binding
|
117
|
+
return t.result(b) if destination.nil?
|
118
|
+
|
133
119
|
dest = opt[:absolute_destination] ? destination : File.join(Config.instance.project_source_path, destination)
|
134
120
|
FileUtils.mkpath File.dirname(dest) unless File.exists? dest
|
135
121
|
scratch = "#{dest}.scratch"
|
@@ -139,30 +125,38 @@ module Cog
|
|
139
125
|
else
|
140
126
|
updated = File.exists? dest
|
141
127
|
FileUtils.mv scratch, dest
|
142
|
-
STDOUT.write "#{updated ? :Updated : :Created} #{dest}\n".color(updated ? :white : :green)
|
128
|
+
STDOUT.write "#{updated ? :Updated : :Created} #{dest.relative_to_project_root}\n".color(updated ? :white : :green) unless opt[:quiet]
|
143
129
|
end
|
144
130
|
nil
|
145
131
|
end
|
146
132
|
|
147
133
|
# Copy a file from +src+ to +dest+, but only if +dest+ does not already exist.
|
148
|
-
|
134
|
+
# @param src [String] where to copy from
|
135
|
+
# @param dest [String] where to copy to
|
136
|
+
# @option opt [Boolean] :quiet (false) suppress writing to STDOUT?
|
137
|
+
# @return [nil]
|
138
|
+
def copy_if_missing(src, dest, opt={})
|
149
139
|
unless File.exists? dest
|
150
140
|
FileUtils.cp src, dest
|
151
|
-
STDOUT.write "Created #{dest}\n".color(:green)
|
141
|
+
STDOUT.write "Created #{dest.relative_to_project_root}\n".color(:green) unless opt[:quiet]
|
152
142
|
end
|
153
143
|
end
|
154
144
|
|
155
145
|
# Recursively create directories in the given path if they are missing.
|
156
|
-
|
157
|
-
|
146
|
+
# @param path [String] a file system path representing a directory
|
147
|
+
# @option opt [Boolean] :quiet (false) suppress writing to STDOUT?
|
148
|
+
# @return [nil]
|
149
|
+
def touch_path(path, opt={})
|
158
150
|
unless File.exists? path
|
159
151
|
FileUtils.mkdir_p path
|
160
|
-
STDOUT.write "Created #{path}\n".color(:green)
|
152
|
+
STDOUT.write "Created #{path.relative_to_project_root}\n".color(:green) unless opt[:quiet]
|
161
153
|
end
|
154
|
+
nil
|
162
155
|
end
|
163
156
|
|
164
157
|
# File extension for a snippet of the given source code language.
|
165
|
-
#
|
158
|
+
# @api unstable
|
159
|
+
# @example
|
166
160
|
# snippet_extension 'c++' # => 'h'
|
167
161
|
def snippet_extension(lang = 'text') # :nodoc:
|
168
162
|
case lang
|
@@ -172,24 +166,20 @@ module Cog
|
|
172
166
|
'txt'
|
173
167
|
end
|
174
168
|
end
|
175
|
-
|
176
|
-
#
|
177
|
-
def
|
178
|
-
lang = Config.instance.language
|
179
|
-
t = get_template "snippets/#{lang}/generated_warning.#{snippet_extension lang}", :cog_template => true
|
180
|
-
t.result(binding)
|
181
|
-
end
|
182
|
-
|
183
|
-
def include_guard_begin(name) # :nodoc:
|
169
|
+
|
170
|
+
# @api unstable
|
171
|
+
def include_guard_begin(name)
|
184
172
|
full = "COG_INCLUDE_GUARD_#{name.upcase}"
|
185
173
|
"#ifndef #{full}\n#define #{full}"
|
186
174
|
end
|
187
175
|
|
188
|
-
|
176
|
+
# @api unstable
|
177
|
+
def include_guard_end
|
189
178
|
"#endif // COG_INCLUDE_GUARD_[...]"
|
190
179
|
end
|
191
180
|
|
192
|
-
|
181
|
+
# @api unstable
|
182
|
+
def namespace_begin(name)
|
193
183
|
return if name.nil?
|
194
184
|
case Config.instance.language
|
195
185
|
when /c\+\+/
|
@@ -197,7 +187,8 @@ module Cog
|
|
197
187
|
end
|
198
188
|
end
|
199
189
|
|
200
|
-
|
190
|
+
# @api unstable
|
191
|
+
def namespace_end(name)
|
201
192
|
return if name.nil?
|
202
193
|
case Config.instance.language
|
203
194
|
when /c\+\+/
|
@@ -206,7 +197,7 @@ module Cog
|
|
206
197
|
end
|
207
198
|
|
208
199
|
private
|
209
|
-
def same?(original, scratch)
|
200
|
+
def same?(original, scratch)
|
210
201
|
if File.exists? original
|
211
202
|
File.read(original) == File.read(scratch)
|
212
203
|
else
|
data/lib/cog/helpers.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'cog/helpers/string'
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'cog/config'
|
2
|
+
|
3
|
+
class String
|
4
|
+
|
5
|
+
# @return [String] strips {Cog::Config#project_root} from the beginning of this string
|
6
|
+
def relative_to_project_root
|
7
|
+
return unless Cog::Config.instance.project?
|
8
|
+
root = Cog::Config.instance.project_root
|
9
|
+
start_with?(root) ? slice(root.length+1..-1) : dup
|
10
|
+
end
|
11
|
+
end
|
data/lib/cog/spec_helpers.rb
CHANGED
@@ -6,15 +6,17 @@ module Cog
|
|
6
6
|
|
7
7
|
# Modules and classes to help write specs for testing +cog+
|
8
8
|
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
# which is returned from a call to SpecHelpers::Runner#run
|
9
|
+
# Requiring the helpers will make extra {SpecHelpers::Matchers} available to
|
10
|
+
# your RSpec tests. These are useful for testing a {SpecHelpers::Invocation},
|
11
|
+
# which is returned from a call to {SpecHelpers::Runner#run}
|
13
12
|
#
|
13
|
+
# @example
|
14
14
|
# require 'cog/spec_helpers'
|
15
15
|
#
|
16
16
|
# describe 'The command line interface' do
|
17
17
|
#
|
18
|
+
# include Cog::SpecHelpers
|
19
|
+
#
|
18
20
|
# before :all do
|
19
21
|
# @cog = Cog::SpecHelpers::Runner.new 'bin/cog'
|
20
22
|
# end
|
@@ -22,42 +24,69 @@ module Cog
|
|
22
24
|
# it 'should print help when no args are passed' do
|
23
25
|
# @cog.run.should show_help
|
24
26
|
# end
|
27
|
+
#
|
28
|
+
# context 'in an uninitialized project' do
|
29
|
+
#
|
30
|
+
# before :each do
|
31
|
+
# use_fixture :uninitialized
|
32
|
+
# end
|
25
33
|
#
|
34
|
+
# it 'running `cog init` should make a Cogfile' do
|
35
|
+
# @cog.run(:init).should make(cogfile_path)
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# end
|
26
39
|
# end
|
27
40
|
module SpecHelpers
|
28
41
|
|
29
|
-
#
|
42
|
+
# @return [String] absolute path to the root spec directory
|
30
43
|
def spec_root
|
31
44
|
File.expand_path File.join(File.dirname(__FILE__), '..', '..', 'spec')
|
32
45
|
end
|
33
46
|
|
34
|
-
#
|
47
|
+
# @return [String] directory of an active spec fixture.
|
35
48
|
def active_fixture_dir
|
36
49
|
File.join spec_root, 'active_fixture'
|
37
50
|
end
|
38
51
|
|
39
|
-
#
|
52
|
+
# @return [String] path to the Cogfile in the active spec fixture
|
40
53
|
def cogfile_path
|
41
54
|
File.join active_fixture_dir, 'Cogfile'
|
42
55
|
end
|
43
56
|
|
44
|
-
#
|
57
|
+
# @return [String] path to the cog directory in the active spec fixture
|
45
58
|
def cog_directory
|
46
59
|
File.join active_fixture_dir, 'cog'
|
47
60
|
end
|
48
61
|
|
49
|
-
#
|
62
|
+
# @param name [String] active fixture generator identifier
|
63
|
+
# @return [String] path to the generator with the given name
|
50
64
|
def generator(name)
|
51
65
|
File.expand_path File.join(active_fixture_dir, 'cog', 'generators', "#{name}.rb")
|
52
66
|
end
|
67
|
+
|
68
|
+
# @param name [String] template identifier (without the .erb extension)
|
69
|
+
# @return [String] absolute file system path to the template
|
70
|
+
def template(name)
|
71
|
+
File.expand_path File.join(active_fixture_dir, 'cog', 'templates', "#{name}")
|
72
|
+
end
|
53
73
|
|
54
|
-
#
|
74
|
+
# @param name [String] tool fixture identifier
|
75
|
+
# @return [String] path to the test tool with the given name
|
55
76
|
def tool(name)
|
56
77
|
File.expand_path File.join(spec_root, 'tools', name.to_s, 'lib', "#{name}.rb")
|
57
78
|
end
|
58
79
|
|
59
|
-
#
|
80
|
+
# @param filename [String] name of a generated source file
|
81
|
+
# @return [String] absolute path to the generated file
|
82
|
+
def generated_file(filename)
|
83
|
+
File.expand_path File.join(active_fixture_dir, 'src', filename)
|
84
|
+
end
|
85
|
+
|
86
|
+
# The next cog spec will execute in a fresh copy of the given fixture
|
60
87
|
# Fixture directories are stored in <tt>spec/fixtures</tt>.
|
88
|
+
# @param name [String] name of the fixture
|
89
|
+
# @return [nil]
|
61
90
|
def use_fixture(name)
|
62
91
|
path = File.join spec_root, 'fixtures', name.to_s
|
63
92
|
if File.exists?(path) && File.directory?(path)
|
@@ -67,6 +96,7 @@ module Cog
|
|
67
96
|
else
|
68
97
|
throw :invalid_fixture_name
|
69
98
|
end
|
99
|
+
nil
|
70
100
|
end
|
71
101
|
|
72
102
|
end
|
@@ -4,11 +4,12 @@ require 'rspec'
|
|
4
4
|
module Cog
|
5
5
|
module SpecHelpers
|
6
6
|
|
7
|
-
# Extra should or should_not matchers for RSpec.
|
8
|
-
# Check out #match_maker for help writing new matchers.
|
7
|
+
# Extra +should+ or +should_not+ matchers for RSpec.
|
8
|
+
# Check out {#match_maker} for help writing new matchers.
|
9
9
|
module Matchers
|
10
10
|
|
11
|
-
# The target Invocation should write something to STDERR, indicating an error
|
11
|
+
# The target {Invocation} should write something to STDERR, indicating an error
|
12
|
+
# @return [nil]
|
12
13
|
def complain
|
13
14
|
match_maker do
|
14
15
|
message { "to [write something|not write anything] to STDERR" }
|
@@ -16,7 +17,9 @@ module Cog
|
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
19
|
-
# The target Invocation should create a
|
20
|
+
# The target {Invocation} should create a file at the given +path+
|
21
|
+
# @param path [String] path to check for a file after the invocation
|
22
|
+
# @return [nil]
|
20
23
|
def make(path)
|
21
24
|
match_maker do
|
22
25
|
message { "to [create|not create] #{path}" }
|
@@ -29,7 +32,8 @@ module Cog
|
|
29
32
|
end
|
30
33
|
end
|
31
34
|
|
32
|
-
# The target Invocation should do something, as determined by standard output
|
35
|
+
# The target {Invocation} should do something, as determined by standard output
|
36
|
+
# @return [nil]
|
33
37
|
def do_something
|
34
38
|
match_maker do
|
35
39
|
message { "to [write something|not write anything] to STDOUT" }
|
@@ -37,7 +41,9 @@ module Cog
|
|
37
41
|
end
|
38
42
|
end
|
39
43
|
|
40
|
-
# The target Invocation should write the given list of lines to standard output
|
44
|
+
# The target {Invocation} should write the given list of lines to standard output
|
45
|
+
# @param x [Array<String>] a list of lines to match against standard output
|
46
|
+
# @return [nil]
|
41
47
|
def output(x)
|
42
48
|
match_maker do
|
43
49
|
message { "to [write|not write] #{x.join "\n"} to STDOUT"}
|
@@ -47,7 +53,8 @@ module Cog
|
|
47
53
|
end
|
48
54
|
end
|
49
55
|
|
50
|
-
# The target Invocation should output the default help text
|
56
|
+
# The target {Invocation} should output the default help text
|
57
|
+
# @return [nil]
|
51
58
|
def show_help
|
52
59
|
match_maker do
|
53
60
|
message { "to [show|not show] the default help text, got #{lines.first.inspect}" }
|
@@ -2,8 +2,8 @@ module Cog
|
|
2
2
|
module SpecHelpers
|
3
3
|
module Matchers
|
4
4
|
|
5
|
-
# Within Matchers#match_maker blocks, +self+ is set to an instance of this
|
6
|
-
# class
|
5
|
+
# Within {Matchers#match_maker} blocks, +self+ is set to an instance of this
|
6
|
+
# class
|
7
7
|
class MatchMaker
|
8
8
|
|
9
9
|
# A list of lines read from STDOUT after executing the Invocation
|
@@ -17,69 +17,91 @@ module Cog
|
|
17
17
|
#
|
18
18
|
# The template is used for both positive and negative failures.
|
19
19
|
# Substrings which look like this <tt>"[positive|negative]</tt>" will
|
20
|
-
# be replaced with the appropriate section.
|
20
|
+
# be replaced with the appropriate section.
|
21
|
+
#
|
22
|
+
# @example
|
21
23
|
# message { "to [show|not show] the default help text" }
|
22
24
|
#
|
23
25
|
# would read "expected cog to show the default help text"
|
24
26
|
# for a positive failure and "expected cog to not show the
|
25
27
|
# default help text" for a negative failure. The "expected cog"
|
26
28
|
# part is inserted automatically.
|
29
|
+
#
|
30
|
+
# @yield called after the invocation. {#lines} and {#error} can be used
|
31
|
+
# @return [nil]
|
27
32
|
def message(&block)
|
28
33
|
@msg_block = block
|
34
|
+
nil
|
29
35
|
end
|
30
36
|
|
31
37
|
# Define a block which runs before the Invocation.
|
32
38
|
#
|
33
39
|
# This is not required, but can be used to save context that is used
|
34
40
|
# the in post invocation #test.
|
41
|
+
#
|
42
|
+
# @yield called before the invocation. Save context as instance variables
|
43
|
+
# @return [nil]
|
35
44
|
def before(&block)
|
36
45
|
@before_block = block
|
46
|
+
nil
|
37
47
|
end
|
38
48
|
|
39
49
|
# Define the test which runs after the Invocation
|
40
50
|
#
|
41
51
|
# This can make use of instance variables set during #before.
|
52
|
+
#
|
53
|
+
# @yield called after the invocation
|
54
|
+
# @return [nil]
|
42
55
|
def test(&block)
|
43
56
|
@test_block = block
|
57
|
+
nil
|
44
58
|
end
|
45
59
|
|
46
|
-
|
47
|
-
|
60
|
+
# @api developer
|
61
|
+
# @param invocation [Invocation] +cog+ executable and arguments bundled up
|
62
|
+
# @return [Boolean] result of the {#test} block
|
63
|
+
def matches?(invocation)
|
64
|
+
@invocation = invocation
|
48
65
|
instance_eval &@before_block unless @before_block.nil?
|
49
|
-
@
|
66
|
+
@invocation.exec do |input, output, error|
|
50
67
|
@lines = output.readlines
|
51
68
|
@error = error.readlines
|
52
69
|
end
|
53
70
|
instance_eval &@test_block
|
54
71
|
end
|
55
|
-
|
72
|
+
|
73
|
+
# @api developer
|
74
|
+
# @return [String] positive interpretation of the {#message} block result
|
75
|
+
def failure_message
|
56
76
|
msg = instance_eval &@msg_block
|
57
77
|
msg = msg.gsub /\[([^\|\]]*)(?:\|([^\]]*)\])?/, '\1'
|
58
|
-
"expected #{@
|
78
|
+
"expected #{@invocation} #{msg}\n#{trace}"
|
59
79
|
end
|
60
|
-
|
80
|
+
|
81
|
+
# @api developer
|
82
|
+
# @return [String] negative interpretation of the {#message} block result
|
83
|
+
def negative_failure_message
|
61
84
|
msg = instance_eval &@msg_block
|
62
85
|
msg = msg.gsub /\[([^\|\]]*)(?:\|([^\]]*)\])?/, '\2'
|
63
|
-
"expected #{@
|
86
|
+
"expected #{@invocation} #{msg}\n#{trace}"
|
64
87
|
end
|
65
88
|
|
66
|
-
|
89
|
+
# @api developer
|
90
|
+
# @return [String] STDOUT and STDERR
|
91
|
+
def trace
|
67
92
|
"STDOUT:\n#{@lines.join "\n"}\nSTDERR:\n#{@error.join "\n"}"
|
68
93
|
end
|
69
94
|
end
|
70
95
|
|
71
|
-
# Makes it
|
72
|
-
#
|
73
|
-
#
|
74
|
-
# #match_maker method.
|
96
|
+
# Makes it easier to write RSpec matchers for testing +cog+ command invocations
|
97
|
+
# @yield +self+ is set to an instance of {MatchMaker}
|
98
|
+
# @example
|
75
99
|
# def show_help
|
76
100
|
# match_maker do
|
77
101
|
# message { "to [show|not show] the default help text, got #{lines.first.inspect}" }
|
78
102
|
# test { (/help.*code gen/ =~ lines[1]) }
|
79
103
|
# end
|
80
104
|
# end
|
81
|
-
#
|
82
|
-
# Within the +match_maker+ block, +self+ is set to an instance of MatchMaker.
|
83
105
|
def match_maker(&block)
|
84
106
|
m = MatchMaker.new
|
85
107
|
m.instance_eval &block
|
@@ -9,16 +9,15 @@ module Cog
|
|
9
9
|
# Value of the COG_TOOLS environment variable for invocations returned from #run
|
10
10
|
attr_accessor :tools
|
11
11
|
|
12
|
+
# @param path_to_cl_app [String] path
|
12
13
|
def initialize(path_to_cl_app)
|
13
14
|
@cog = File.expand_path path_to_cl_app
|
14
15
|
@tools = []
|
15
16
|
end
|
16
17
|
|
17
18
|
# Run cog with the given arguments
|
18
|
-
#
|
19
|
-
#
|
20
|
-
# An instance of Invocation configured with the arguments. Use should and
|
21
|
-
# should_not with the custom Matchers
|
19
|
+
# @param args [Array<String>] arguments to pass to +cog+
|
20
|
+
# @return [Invocation] an object which can be used with custom {Matchers}
|
22
21
|
def run(*args)
|
23
22
|
args = [@cog] + args
|
24
23
|
Invocation.new(args.collect {|x| x.to_s}, :tools => @tools)
|
@@ -26,16 +25,23 @@ module Cog
|
|
26
25
|
end
|
27
26
|
|
28
27
|
# Represents a +cog+ command line invocation, which can be tested with
|
29
|
-
# +RSpec+ +should+ and +should_not+ custom Matchers. This is the kind of
|
30
|
-
# object returned by Runner#run.
|
28
|
+
# +RSpec+ +should+ and +should_not+ custom {Matchers}. This is the kind of
|
29
|
+
# object returned by {Runner#run}.
|
31
30
|
class Invocation
|
32
31
|
|
33
|
-
|
32
|
+
# @api developer
|
33
|
+
# @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
|
+
def initialize(cmd, opt={})
|
34
36
|
@cmd = cmd
|
35
|
-
@tools = opt[:tools].join ':'
|
37
|
+
@tools = (opt[:tools] || []).join ':'
|
36
38
|
end
|
37
39
|
|
38
|
-
|
40
|
+
# Execute the command
|
41
|
+
# @api developer
|
42
|
+
# @yield [stdin, stdout, stderr] standard pipes for the invocation
|
43
|
+
# @return [nil]
|
44
|
+
def exec(&block)
|
39
45
|
@cmd = ['bundle', 'exec'] + @cmd
|
40
46
|
ENV['COG_TOOLS'] = @tools
|
41
47
|
Open3.popen3 *@cmd do |i,o,e,t|
|
@@ -43,7 +49,9 @@ module Cog
|
|
43
49
|
end
|
44
50
|
end
|
45
51
|
|
46
|
-
|
52
|
+
# @api developer
|
53
|
+
# @return [String] loggable representation
|
54
|
+
def to_s
|
47
55
|
"`COG_TOOLS=#{@tools} #{@cmd.compact.join ' '}`"
|
48
56
|
end
|
49
57
|
end
|
data/lib/cog/tool.rb
CHANGED
@@ -4,10 +4,12 @@ require 'rainbow'
|
|
4
4
|
|
5
5
|
module Cog
|
6
6
|
|
7
|
-
#
|
7
|
+
# @see https://github.com/ktonon/cog#tools Introduction to Tools
|
8
8
|
class Tool
|
9
9
|
|
10
10
|
# A list of available tools
|
11
|
+
# @param verbose [Boolean] should full paths be listed for tools which are explicitly referenced?
|
12
|
+
# @return [Array<String>] a list of strings which can be passed to +require+
|
11
13
|
def self.list(verbose=false)
|
12
14
|
x = (ENV['COG_TOOLS'] || '').split ':'
|
13
15
|
if x.all? {|path| path.slice(-3..-1) != '.rb' || File.exists?(path)}
|
@@ -29,9 +31,8 @@ module Cog
|
|
29
31
|
end
|
30
32
|
|
31
33
|
# Generate a new tool with the given name
|
32
|
-
#
|
33
|
-
#
|
34
|
-
# Whether or not the generator was created successfully
|
34
|
+
# @param name [String] name of the tool to create. Should not conflict with other tool names
|
35
|
+
# @return [Boolean] was the tool created successfully?
|
35
36
|
def self.create(name)
|
36
37
|
if File.exists? name
|
37
38
|
STDERR.write "A #{File.directory?(name) ? :directory : :file} named '#{name}' already exists\n".color(:red)
|
@@ -62,9 +63,8 @@ module Cog
|
|
62
63
|
end
|
63
64
|
|
64
65
|
# Find an available tool with the given name
|
65
|
-
#
|
66
|
-
#
|
67
|
-
# A fully qualified tool path, which can be required
|
66
|
+
# @param name [String] name of the tool to search for
|
67
|
+
# @return [String] a fully qualified tool path, which can be passed to +require+
|
68
68
|
def self.find(name)
|
69
69
|
x = (ENV['COG_TOOLS'] || '').split ':'
|
70
70
|
x.each do |path|
|
data/lib/cog/version.rb
CHANGED
File without changes
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cog
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 55
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 20
|
10
|
+
version: 0.0.20
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Kevin Tonon
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-11-
|
18
|
+
date: 2012-11-07 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: gli
|
@@ -60,7 +60,7 @@ dependencies:
|
|
60
60
|
type: :development
|
61
61
|
version_requirements: *id003
|
62
62
|
- !ruby/object:Gem::Dependency
|
63
|
-
name:
|
63
|
+
name: yard
|
64
64
|
prerelease: false
|
65
65
|
requirement: &id004 !ruby/object:Gem::Requirement
|
66
66
|
none: false
|
@@ -79,16 +79,14 @@ executables:
|
|
79
79
|
- cog
|
80
80
|
extensions: []
|
81
81
|
|
82
|
-
extra_rdoc_files:
|
83
|
-
|
82
|
+
extra_rdoc_files: []
|
83
|
+
|
84
84
|
files:
|
85
85
|
- bin/cog
|
86
86
|
- Default.cogfile
|
87
87
|
- LICENSE
|
88
88
|
- templates/cog/generator/basic-template.txt.erb.erb
|
89
89
|
- templates/cog/generator/basic.rb.erb
|
90
|
-
- templates/cog/snippets/c++/generated_warning.h.erb
|
91
|
-
- templates/cog/snippets/generated_warning.txt
|
92
90
|
- templates/cog/tool/API.rdoc.erb
|
93
91
|
- templates/cog/tool/Gemfile.erb
|
94
92
|
- templates/cog/tool/generator.rb.erb.erb
|
@@ -99,10 +97,13 @@ files:
|
|
99
97
|
- templates/cog/tool/tool.gemspec.erb
|
100
98
|
- templates/cog/tool/tool.rb.erb
|
101
99
|
- templates/cog/tool/version.rb.erb
|
100
|
+
- templates/warning.h.erb
|
102
101
|
- lib/cog/config/cogfile.rb
|
103
102
|
- lib/cog/config.rb
|
104
103
|
- lib/cog/errors.rb
|
105
104
|
- lib/cog/generator.rb
|
105
|
+
- lib/cog/helpers/string.rb
|
106
|
+
- lib/cog/helpers.rb
|
106
107
|
- lib/cog/spec_helpers/matchers/match_maker.rb
|
107
108
|
- lib/cog/spec_helpers/matchers.rb
|
108
109
|
- lib/cog/spec_helpers/runner.rb
|
@@ -110,17 +111,13 @@ files:
|
|
110
111
|
- lib/cog/tool.rb
|
111
112
|
- lib/cog/version.rb
|
112
113
|
- lib/cog.rb
|
113
|
-
-
|
114
|
+
- yard-templates/default/fulldoc/html/css/common.css
|
114
115
|
homepage: https://github.com/ktonon/cog
|
115
116
|
licenses: []
|
116
117
|
|
117
118
|
post_install_message:
|
118
|
-
rdoc_options:
|
119
|
-
|
120
|
-
- cog
|
121
|
-
- --main
|
122
|
-
- cog.rdoc
|
123
|
-
- -ri
|
119
|
+
rdoc_options: []
|
120
|
+
|
124
121
|
require_paths:
|
125
122
|
- lib
|
126
123
|
- lib
|
data/API.rdoc
DELETED