cog 0.0.10 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/API.rdoc +4 -31
  2. data/Default.cogfile +8 -5
  3. data/bin/cog +61 -51
  4. data/lib/cog.rb +18 -2
  5. data/lib/cog/config.rb +60 -42
  6. data/lib/cog/config/cogfile.rb +76 -0
  7. data/lib/cog/errors.rb +16 -0
  8. data/lib/cog/generator.rb +138 -0
  9. data/lib/cog/spec_helpers.rb +35 -0
  10. data/lib/cog/spec_helpers/matchers.rb +17 -17
  11. data/lib/cog/spec_helpers/matchers/match_maker.rb +51 -0
  12. data/lib/cog/spec_helpers/runner.rb +9 -5
  13. data/lib/cog/tool.rb +51 -0
  14. data/lib/cog/version.rb +3 -0
  15. data/templates/{snippets → cog/snippets}/c++/generated_warning.h.erb +0 -0
  16. data/templates/{snippets → cog/snippets}/generated_warning.txt +0 -0
  17. data/templates/cog/tool/API.rdoc.erb +7 -0
  18. data/templates/cog/tool/Gemfile.erb +4 -0
  19. data/templates/cog/tool/LICENSE.erb +18 -0
  20. data/templates/cog/tool/README.markdown.erb +18 -0
  21. data/templates/cog/tool/Rakefile.erb +15 -0
  22. data/templates/cog/tool/generator.rb.erb +5 -0
  23. data/templates/cog/tool/tool.gemspec.erb +18 -0
  24. data/templates/cog/tool/tool.rb.erb +4 -0
  25. data/templates/cog/tool/version.rb.erb +5 -0
  26. metadata +21 -19
  27. data/lib/cog/cogfile.rb +0 -65
  28. data/lib/cog/meta.rb +0 -9
  29. data/lib/cog/meta/gen_gen.rb +0 -85
  30. data/lib/cog/meta/mirror_gen.rb +0 -39
  31. data/lib/cog/mixins.rb +0 -13
  32. data/lib/cog/mixins/mirror.rb +0 -61
  33. data/lib/cog/mixins/uses_templates.rb +0 -152
  34. data/lib/cog_version.rb +0 -3
  35. data/templates/c++/mirror-abstract.cpp.erb +0 -0
  36. data/templates/c++/mirror-abstract.h.erb +0 -6
  37. data/templates/c++/mirror-impl.cpp.erb +0 -1
  38. data/templates/c++/mirror-impl.h.erb +0 -0
  39. data/templates/mirror.rb.erb +0 -10
@@ -0,0 +1,138 @@
1
+ require 'cog/config'
2
+ require 'cog/errors'
3
+ require 'erb'
4
+
5
+ module Cog
6
+
7
+ # Generators have the ability to #stamp templates into source code.
8
+ #
9
+ # This module defines a low-level interface for writing generators. To use it,
10
+ # just include the Generator module in your class or object.
11
+ module Generator
12
+
13
+ # A list of available project generators
14
+ def self.available
15
+ [:dummy1, :dummy2]
16
+ end
17
+
18
+ # Get the template with the given name.
19
+ #
20
+ # ==== Parameters
21
+ # * +path+ - a path to a template file which is relative to
22
+ # one of the template directories
23
+ #
24
+ # ==== Options
25
+ # * <tt>:absolute</tt> - is the +path+ argument absolute? (default: +false+)
26
+ #
27
+ # ==== Returns
28
+ # An instance of ERB.
29
+ def get_template(path, opt={})
30
+ path += '.erb'
31
+ fullpath = if opt[:absolute]
32
+ path
33
+ else
34
+ Config.instance.template_paths.inject('') do |found, prefix|
35
+ x = File.join prefix, path
36
+ found.empty? && File.exists?(x) ? x : found
37
+ end
38
+ end
39
+ raise Errors::MissingTemplate.new fullpath unless File.exists? fullpath
40
+ ERB.new File.read(fullpath), 0, '>'
41
+ end
42
+
43
+ # Stamp a template +source+ onto a +destination+.
44
+ #
45
+ # ==== Arguments
46
+ # * +template_path+ - a path to a template file which is relative to one
47
+ # of the template directories
48
+ # * +destination+ - a path to which the generated file should be written
49
+ #
50
+ # ==== Options
51
+ # * <tt>:absolute_template_path</tt> - is the +template_path+ argument absolute? (default: +false+)
52
+ def stamp(template_path, destination, opt={})
53
+ t = get_template template_path, :absolute => opt[:absolute_template_path]
54
+ b = opt[:binding] || binding
55
+ FileUtils.mkpath File.dirname(destination) unless File.exists? destination
56
+ scratch = "#{destination}.scratch"
57
+ File.open(scratch, 'w') {|file| file.write t.result(b)}
58
+ if same? destination, scratch
59
+ FileUtils.rm scratch
60
+ else
61
+ puts "Generated #{destination}"
62
+ FileUtils.mv scratch, destination
63
+ end
64
+ nil
65
+ end
66
+
67
+ # Copy a file from +src+ to +dest+, but only if +dest+ does not already exist.
68
+ def copy_if_missing(src, dest)
69
+ unless File.exists? dest
70
+ FileUtils.cp src, dest
71
+ puts "Created #{dest}"
72
+ end
73
+ end
74
+
75
+ # Recursively create directories in the given path if they are missing.
76
+ def touch_path(*path_components)
77
+ path = File.join path_components
78
+ unless File.exists? path
79
+ FileUtils.mkdir_p path
80
+ puts "Created #{path}"
81
+ end
82
+ end
83
+
84
+ # File extension for a snippet of the given source code language.
85
+ # ==== Example
86
+ # snippet_extension 'c++' # => 'h'
87
+ def snippet_extension(lang = 'text')
88
+ case lang
89
+ when /(c\+\+|c|objc)/i
90
+ 'h'
91
+ else
92
+ 'txt'
93
+ end
94
+ end
95
+
96
+ # A warning that indicates a file is maintained by a generator
97
+ def generated_warning
98
+ lang = Config.instance.language
99
+ t = get_template "snippets/#{lang}/generated_warning.#{snippet_extension lang}", :cog_template => true
100
+ t.result(binding)
101
+ end
102
+
103
+ def include_guard_begin(name)
104
+ full = "COG_INCLUDE_GUARD_#{name.upcase}"
105
+ "#ifndef #{full}\n#define #{full}"
106
+ end
107
+
108
+ def include_guard_end
109
+ "#endif // COG_INCLUDE_GUARD_[...]"
110
+ end
111
+
112
+ def namespace_begin(name)
113
+ return if name.nil?
114
+ case Config.instance.language
115
+ when /c\+\+/
116
+ "namespace #{name} {"
117
+ end
118
+ end
119
+
120
+ def namespace_end(name)
121
+ return if name.nil?
122
+ case Config.instance.language
123
+ when /c\+\+/
124
+ "} // namespace #{name}"
125
+ end
126
+ end
127
+
128
+ private
129
+ def same?(original, scratch) # :nodoc:
130
+ if File.exists? original
131
+ File.read(original) == File.read(scratch)
132
+ else
133
+ false
134
+ end
135
+ end
136
+
137
+ end
138
+ end
@@ -1,5 +1,6 @@
1
1
  require 'cog/spec_helpers/runner'
2
2
  require 'cog/spec_helpers/matchers'
3
+ require 'fileutils'
3
4
 
4
5
  module Cog
5
6
 
@@ -24,6 +25,40 @@ module Cog
24
25
  #
25
26
  # end
26
27
  module SpecHelpers
28
+
29
+ # Absolute path to the root spec directory
30
+ def spec_root
31
+ File.expand_path File.join(File.dirname(__FILE__), '..', '..', 'spec')
32
+ end
33
+
34
+ # Directory of an active spec fixture.
35
+ def active_fixture_dir
36
+ File.join spec_root, 'active_fixture'
37
+ end
38
+
39
+ # Path to the Cogfile in the active spec fixture
40
+ def cogfile_path
41
+ File.join active_fixture_dir, 'Cogfile'
42
+ end
43
+
44
+ # Path to the cog directory in the active spec fixture
45
+ def cog_directory
46
+ File.join active_fixture_dir, 'cog'
47
+ end
48
+
49
+ # The next cog spec will execute in a fresh copy of the given fixture directory.
50
+ # Fixture directories are stored in <tt>spec/fixtures</tt>.
51
+ def use_fixture(name)
52
+ path = File.join spec_root, 'fixtures', name.to_s
53
+ if File.exists?(path) && File.directory?(path)
54
+ FileUtils.rmtree active_fixture_dir if File.exists? active_fixture_dir
55
+ FileUtils.cp_r path, active_fixture_dir
56
+ Dir.chdir active_fixture_dir
57
+ else
58
+ throw :invalid_fixture_name
59
+ end
60
+ end
61
+
27
62
  end
28
63
 
29
64
  end
@@ -1,3 +1,4 @@
1
+ require 'cog/spec_helpers/matchers/match_maker'
1
2
  require 'rspec'
2
3
 
3
4
  module Cog
@@ -6,26 +7,25 @@ module Cog
6
7
  # Extra should or should_not matchers for RSpec.
7
8
  module Matchers
8
9
 
9
- class ShowHelp # :nodoc:
10
- def matches?(runner)
11
- @runner = runner
12
- @runner.exec do |i,o,e|
13
- @first_line = o.readline
14
- @second_line = o.readline
15
- /help.*code gen/ =~ @second_line
16
- end
17
- end
18
- def failure_message
19
- "expected #{@runner} to show the default help text, got #{@first_line.inspect}"
20
- end
21
- def negative_failure_message
22
- "expected #{@runner} to not show the default help text, got #{@first_line.inspect}"
10
+ # The target Invocation should output the default help text
11
+ def show_help
12
+ match_maker do
13
+ message { "to [show|not show] the default help text, got #{lines.first.inspect}" }
14
+ test { (/help.*code gen/ =~ lines[1]) }
23
15
  end
24
16
  end
25
17
 
26
- # The target Invocation should output the default help text
27
- def show_help
28
- ShowHelp.new
18
+ # The target Invocation should create a +Cogfile+ where none existed before
19
+ def make(path)
20
+ match_maker do
21
+ message { "to [create|not create] the #{path}" }
22
+ before do
23
+ @existed = File.exists? path
24
+ end
25
+ test do
26
+ !@existed && File.exists?(path)
27
+ end
28
+ end
29
29
  end
30
30
  end
31
31
 
@@ -0,0 +1,51 @@
1
+ module Cog
2
+ module SpecHelpers
3
+ module Matchers
4
+
5
+ class MatchMaker
6
+ attr_reader :lines
7
+
8
+ # Define the failure message
9
+ def message(&block)
10
+ @msg_block = block
11
+ end
12
+
13
+ # Define a block which runs before the Invocation
14
+ def before(&block)
15
+ @before_block = block
16
+ end
17
+
18
+ # Define the test which runs after the Invocation
19
+ def test(&block)
20
+ @test_block = block
21
+ end
22
+
23
+ def matches?(runner) # :nodoc:
24
+ @runner = runner
25
+ instance_eval &@before_block unless @before_block.nil?
26
+ @runner.exec do |input, output, error|
27
+ @lines = output.readlines
28
+ end
29
+ instance_eval &@test_block
30
+ end
31
+ def failure_message # :nodoc:
32
+ msg = instance_eval &@msg_block
33
+ msg = msg.gsub /\[([^\|\]]*)(?:\|([^\]]*)\])?/, '\1'
34
+ "expected #{@runner} #{msg}"
35
+ end
36
+ def negative_failure_message # :nodoc:
37
+ msg = instance_eval &@msg_block
38
+ msg = msg.gsub /\[([^\|\]]*)(?:\|([^\]]*)\])?/, '\2'
39
+ "expected #{@runner} #{msg}"
40
+ end
41
+ end
42
+
43
+ def match_maker(&block)
44
+ m = MatchMaker.new
45
+ m.instance_eval &block
46
+ m
47
+ end
48
+
49
+ end
50
+ end
51
+ end
@@ -4,10 +4,10 @@ module Cog
4
4
  module SpecHelpers
5
5
 
6
6
  # Points to the +cog+ command-line app
7
- class App
7
+ class Runner
8
8
 
9
9
  def initialize(path_to_cl_app)
10
- @cog = path_to_cl_app
10
+ @cog = File.expand_path path_to_cl_app
11
11
  end
12
12
 
13
13
  # Run cog with the given arguments
@@ -16,8 +16,8 @@ module Cog
16
16
  # An instance of Invocation configured with the arguments. Use should and
17
17
  # should_not with the custom Matchers
18
18
  def run(*args)
19
- args.unshift @cog
20
- Invocation.new args
19
+ args = ['bundle', 'exec', @cog] + args
20
+ Invocation.new(args.collect {|x| x.to_s})
21
21
  end
22
22
  end
23
23
 
@@ -30,11 +30,15 @@ module Cog
30
30
  end
31
31
 
32
32
  def exec(*args, &block) # :nodoc:
33
+ @s = ([File.basename @cmd[2]] + @cmd.slice(3..-1)).join ' '
33
34
  Open3.popen3 *@cmd do |i,o,e,t|
34
35
  block.call i,o,e
35
36
  end
36
37
  end
37
-
38
+
39
+ def to_s
40
+ "`#{@s}`"
41
+ end
38
42
  end
39
43
 
40
44
  end
@@ -0,0 +1,51 @@
1
+ require 'cog/config'
2
+ require 'cog/generator'
3
+
4
+ module Cog
5
+
6
+ class Tool
7
+
8
+ # Lower case command-line version of the name
9
+ attr_reader :name
10
+
11
+ # Capitalized module name
12
+ attr_reader :module_name
13
+
14
+ # Name of the person who will be given copyright for the generated code
15
+ attr_reader :author
16
+
17
+ # Email address of the author
18
+ attr_reader :email
19
+
20
+ # A one-line description of the tool
21
+ attr_reader :description
22
+
23
+ # A list of available tools
24
+ def self.available
25
+ # TODO: use paths to instantiate a list of Tool objects
26
+ paths = ENV['COG_TOOLS'] || []
27
+ end
28
+
29
+ def self.generate_tool(name)
30
+ Object.new.instance_eval do
31
+ class << self ; include Generator ; end
32
+ @name = name.to_s.downcase
33
+ @module_name = name.to_s.capitalize
34
+ @author = '<Your name goes here>'
35
+ @email = 'youremail@...'
36
+ @description = 'A one-liner'
37
+ @cog_version = Cog::VERSION
38
+ stamp 'cog/tool/tool.rb', "#{@name}/lib/#{@name}.rb"
39
+ stamp 'cog/tool/version.rb', "#{@name}/lib/#{@name}/version.rb"
40
+ stamp 'cog/tool/generator.rb', "#{@name}/cog/templates/#{@name}/generator.rb.erb"
41
+ stamp 'cog/tool/Gemfile', "#{@name}/Gemfile"
42
+ stamp 'cog/tool/Rakefile', "#{@name}/Rakefile"
43
+ stamp 'cog/tool/tool.gemspec', "#{@name}/#{@name}.gemspec"
44
+ stamp 'cog/tool/API.rdoc', "#{@name}/API.rdoc"
45
+ stamp 'cog/tool/LICENSE', "#{@name}/LICENSE"
46
+ stamp 'cog/tool/README.markdown', "#{@name}/README.markdown"
47
+ end
48
+ end
49
+ end
50
+
51
+ end
@@ -0,0 +1,3 @@
1
+ module Cog
2
+ VERSION = '0.0.11' unless const_defined? :VERSION
3
+ end
@@ -0,0 +1,7 @@
1
+ = <%= @name %>
2
+
3
+ These are the API docs for +<%= @name %>+, which is +cog+ tool.
4
+
5
+ Please see the <tt>README.markdown</tt> file for a introduction to the
6
+ +<%= @name %>+ tool. To find out more about +cog+ in general visit
7
+ https://github.com/ktonon/cog#readme
@@ -0,0 +1,4 @@
1
+ source :rubygems
2
+ gemspec
3
+
4
+ gem "cog", "~> <%= @cog_version %>"
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2012 <%= @author %>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7
+ the Software, and to permit persons to whom the Software is furnished to do so,
8
+ subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,18 @@
1
+ = <%= @name %>
2
+
3
+ <%= @description %>
4
+
5
+ Get it
6
+ ------
7
+
8
+ From a terminal
9
+
10
+ ```bash
11
+ gem install <%= @name %>
12
+ ```
13
+
14
+ or in your Gemfile
15
+
16
+ ```ruby
17
+ gem "<%= @name %>", "~> 0.0.1"
18
+ ```
@@ -0,0 +1,15 @@
1
+ require 'rake/clean'
2
+ require 'rubygems'
3
+ require 'rubygems/package_task'
4
+ require 'rdoc/task'
5
+
6
+ Rake::RDocTask.new do |rd|
7
+ rd.main = "API.rdoc"
8
+ rd.rdoc_files.include("API.rdoc", "lib/**/*.rb")
9
+ rd.title = '<%= @module_name %> API Docs'
10
+ end
11
+
12
+ spec = eval(File.read('<%= @name %>.gemspec'))
13
+
14
+ Gem::PackageTask.new(spec) do |pkg|
15
+ end