cog 0.0.19 → 0.0.20

Sign up to get free protection for your applications and to get access to all the features.
data/lib/cog.rb CHANGED
@@ -4,11 +4,13 @@ require 'cog/tool'
4
4
  require 'cog/version'
5
5
  require 'fileutils'
6
6
 
7
- # The static methods on this top level module mirror the commands available to
8
- # the +cog+ command line utility.
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
 
@@ -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::instance should be configured using
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
- # Path to the project's +Cogfile+.
12
+ # @return [String] path to the project's {Cogfile}
13
13
  attr_reader :cogfile_path
14
14
 
15
- # Default language in which to generated application source code
15
+ # @return [String] default language in which to generated application source code
16
16
  attr_reader :language
17
17
 
18
- # Directory in which to find project generators
18
+ # @return [String] directory in which to find project generators
19
19
  attr_reader :project_generators_path
20
20
 
21
- # Directory in which the project's +Cogfile+ is found
21
+ # @return [String] directory in which the project's {Cogfile} is found
22
22
  attr_reader :project_root
23
23
 
24
- # Directory to which project source code is generated
24
+ # @return [String] directory to which project source code is generated
25
25
  attr_reader :project_source_path
26
26
 
27
- # Directory in which to find custom project templates
27
+ # @return [String] directory in which to find custom project templates
28
28
  attr_reader :project_templates_path
29
29
 
30
- # Are we operating in the context of a project?
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
- # A value which is set by the active tool
35
+ # @param value [String] a value which is set by the active tool
37
36
  attr_writer :tool_templates_path
38
37
 
39
- # A value which is set by the active tool
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
- # Priority should be given first to last.
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
- def self.gem_dir # :nodoc:
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
- # ==== Returns
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
@@ -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
- # ==== Example +Cogfile+
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
- def initialize(config) # :nodoc:
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 and initialize @config
22
- def interpret # :nodoc:
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
- # ==== Arguments
30
- # * +path+ - A file system path
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
- # ==== Arguments
40
- # * +path+ - A file system path
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
- # ==== Arguments
50
- # * +path+ - A file system path
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
- # ==== Arguments
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 +Cogfile+.
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
@@ -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
- # For more details on writing generators see https://github.com/ktonon/cog#generators
13
+ # @see https://github.com/ktonon/cog#generators Introduction to Generators
13
14
  module Generator
14
15
 
15
- # A list of available project generators
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
- # ==== Arguments
28
- # * +name+ - the name to use for the new generator
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
- # ==== Arguments
77
- # * +name+ - the name of the generator
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
- # ==== Parameters
98
- # * +path+ - a path to a template file which is relative to
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 +source+ onto a +destination+.
121
- #
122
- # ==== Arguments
123
- # * +template_path+ - a path to a template file which is relative to one
124
- # of the template directories
125
- # * +destination+ - a path to which the generated file should be written
126
- #
127
- # ==== Options
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
- def copy_if_missing(src, dest)
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
- def touch_path(*path_components)
157
- path = File.join path_components
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
- # ==== Example
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
- # A warning that indicates a file is maintained by a generator
177
- def generated_warning # :nodoc:
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
- def include_guard_end # :nodoc:
176
+ # @api unstable
177
+ def include_guard_end
189
178
  "#endif // COG_INCLUDE_GUARD_[...]"
190
179
  end
191
180
 
192
- def namespace_begin(name) # :nodoc:
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
- def namespace_end(name) # :nodoc:
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) # :nodoc:
200
+ def same?(original, scratch)
210
201
  if File.exists? original
211
202
  File.read(original) == File.read(scratch)
212
203
  else
@@ -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
@@ -6,15 +6,17 @@ module Cog
6
6
 
7
7
  # Modules and classes to help write specs for testing +cog+
8
8
  #
9
- # === Example
10
- # Requiring the helpers will make extra SpecHelpers::Matchers available to
11
- # your RSpec tests. These are useful for testing a SpecHelpers::Invocation,
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
- # Absolute path to the root spec directory
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
- # Directory of an active spec fixture.
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
- # Path to the Cogfile in the active spec fixture
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
- # Path to the cog directory in the active spec fixture
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
- # Path to the generator with the given name
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
- # Path to the test tool with the given name
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
- # The next cog spec will execute in a fresh copy of the given fixture directory.
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 +Cogfile+ where none existed before
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. For example
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
- def matches?(runner) # :nodoc:
47
- @runner = runner
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
- @runner.exec do |input, output, error|
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
- def failure_message # :nodoc:
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 #{@runner} #{msg}\n#{trace}"
78
+ "expected #{@invocation} #{msg}\n#{trace}"
59
79
  end
60
- def negative_failure_message # :nodoc:
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 #{@runner} #{msg}\n#{trace}"
86
+ "expected #{@invocation} #{msg}\n#{trace}"
64
87
  end
65
88
 
66
- def trace # :nodoc
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 easy to write RSpec matchers
72
- #
73
- # Here is how the matcher for Matchers#show_help is written using this method
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
- # === Returns
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
- def initialize(cmd, opt={}) # :nodoc:
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
- def exec(*args, &block) # :nodoc:
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
- def to_s # :nodoc:
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
@@ -4,10 +4,12 @@ require 'rainbow'
4
4
 
5
5
  module Cog
6
6
 
7
- # For more details on writing tools see https://github.com/ktonon/cog#tools
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
- # ==== Returns
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
- # ==== Returns
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|
@@ -1,3 +1,5 @@
1
1
  module Cog
2
- VERSION = '0.0.19' unless const_defined? :VERSION
2
+ unless const_defined? :VERSION
3
+ VERSION = '0.0.20'
4
+ end
3
5
  end
@@ -0,0 +1,6 @@
1
+ #toc {
2
+ -webkit-box-shadow: 0px 0px 2px #bbb;
3
+ }
4
+ #search a:link, #search a:visited {
5
+ -webkit-box-shadow: 0px 0px 2px #eee;
6
+ }
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: 57
4
+ hash: 55
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 19
10
- version: 0.0.19
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-05 00:00:00 Z
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: rdoc
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
- - API.rdoc
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
- - API.rdoc
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
- - --title
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
@@ -1,6 +0,0 @@
1
- = cog API Docs
2
-
3
- +cog+ is a command line tool which helps you write code generators.
4
-
5
- This is the API docs. For a more general introduction to +cog+ visit
6
- https://github.com/ktonon/cog#readme
@@ -1,7 +0,0 @@
1
- WARNING
2
-
3
- This is a generated file. DO NOT EDIT THIS FILE! Your changes will be lost
4
- the next time this file is regenerated.
5
-
6
- This file was generating using cog
7
- https://github.com/ktonon/cog