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.
Files changed (79) hide show
  1. data/BuiltIn.cogfile +96 -0
  2. data/bin/cog +30 -39
  3. data/built_in/generators/sort.rb +3 -0
  4. data/built_in/plugins/basic/Cogfile +6 -0
  5. data/built_in/plugins/basic/templates/basic/generator.rb.erb +1 -0
  6. data/built_in/templates/cog/Cogfile.erb +40 -0
  7. data/built_in/templates/cog/plugin/generator.rb.erb.erb +3 -0
  8. data/{templates/cog/custom_tool/tool.rb.erb → built_in/templates/cog/plugin/plugin.rb.erb} +4 -11
  9. data/{templates → built_in/templates}/warning.erb +0 -0
  10. data/lib/cog.rb +25 -11
  11. data/lib/cog/config.rb +112 -49
  12. data/lib/cog/config/{language_methods.rb → language_config.rb} +23 -27
  13. data/lib/cog/config/plugin_config.rb +31 -0
  14. data/lib/cog/config/project_config.rb +48 -0
  15. data/lib/cog/controllers.rb +6 -8
  16. data/lib/cog/controllers/generator_controller.rb +30 -21
  17. data/lib/cog/controllers/plugin_controller.rb +43 -0
  18. data/lib/cog/controllers/template_controller.rb +12 -33
  19. data/lib/cog/dsl.rb +9 -0
  20. data/lib/cog/dsl/cogfile.rb +145 -0
  21. data/lib/cog/dsl/language_dsl.rb +142 -0
  22. data/lib/cog/embed_context.rb +0 -2
  23. data/lib/cog/embeds.rb +2 -7
  24. data/lib/cog/errors.rb +11 -24
  25. data/lib/cog/generator.rb +10 -15
  26. data/lib/cog/generator/file_methods.rb +2 -2
  27. data/lib/cog/generator/filters.rb +10 -14
  28. data/lib/cog/generator/language_methods.rb +2 -3
  29. data/lib/cog/generator_sandbox.rb +32 -0
  30. data/lib/cog/helpers.rb +10 -2
  31. data/lib/cog/helpers/cascading_set.rb +104 -0
  32. data/lib/cog/{embeds → helpers}/file_scanner.rb +1 -1
  33. data/lib/cog/language.rb +140 -0
  34. data/lib/cog/native_extensions.rb +2 -0
  35. data/lib/cog/native_extensions/array.rb +19 -0
  36. data/lib/cog/native_extensions/string.rb +54 -0
  37. data/lib/cog/plugin.rb +35 -0
  38. data/lib/cog/spec_helpers.rb +36 -14
  39. data/lib/cog/spec_helpers/matchers.rb +14 -4
  40. data/lib/cog/spec_helpers/matchers/match_maker.rb +1 -1
  41. data/lib/cog/spec_helpers/runner.rb +3 -9
  42. data/lib/cog/version.rb +1 -1
  43. metadata +27 -44
  44. data/Default.cogfile +0 -25
  45. data/lib/cog/built_in_tools.rb +0 -9
  46. data/lib/cog/built_in_tools/basic.rb +0 -10
  47. data/lib/cog/built_in_tools/basic/cog_tool.rb +0 -11
  48. data/lib/cog/config/cogfile.rb +0 -117
  49. data/lib/cog/config/lang_info.rb +0 -40
  50. data/lib/cog/config/project_methods.rb +0 -35
  51. data/lib/cog/config/tool_methods.rb +0 -94
  52. data/lib/cog/controllers/tool_controller.rb +0 -50
  53. data/lib/cog/helpers/cascading_template_set.rb +0 -75
  54. data/lib/cog/helpers/string.rb +0 -26
  55. data/lib/cog/languages.rb +0 -52
  56. data/lib/cog/languages/c_language.rb +0 -29
  57. data/lib/cog/languages/c_plus_plus_language.rb +0 -28
  58. data/lib/cog/languages/c_sharp_language.rb +0 -24
  59. data/lib/cog/languages/java_language.rb +0 -24
  60. data/lib/cog/languages/java_script_language.rb +0 -24
  61. data/lib/cog/languages/language.rb +0 -73
  62. data/lib/cog/languages/mixins.rb +0 -10
  63. data/lib/cog/languages/mixins/c_style_comments.rb +0 -23
  64. data/lib/cog/languages/mixins/hash_comments.rb +0 -19
  65. data/lib/cog/languages/python_language.rb +0 -20
  66. data/lib/cog/languages/qt_project_language.rb +0 -16
  67. data/lib/cog/languages/ruby_language.rb +0 -28
  68. data/lib/cog/tool.rb +0 -61
  69. data/lib/cog/tool/dsl.rb +0 -26
  70. data/templates/basic/generator.rb.erb +0 -4
  71. data/templates/cog/custom_tool/Gemfile.erb +0 -8
  72. data/templates/cog/custom_tool/LICENSE.erb +0 -18
  73. data/templates/cog/custom_tool/README.markdown.erb +0 -18
  74. data/templates/cog/custom_tool/Rakefile.erb +0 -15
  75. data/templates/cog/custom_tool/cog_tool.rb.erb +0 -17
  76. data/templates/cog/custom_tool/generator.rb.erb.erb +0 -9
  77. data/templates/cog/custom_tool/template.txt.erb.erb +0 -1
  78. data/templates/cog/custom_tool/tool.gemspec.erb +0 -17
  79. data/templates/cog/custom_tool/version.rb.erb +0 -5
@@ -1,5 +1,5 @@
1
1
  module Cog
2
- module Embeds
2
+ module Helpers
3
3
 
4
4
  # @api developer
5
5
  # Helper for scanning files for embed expansions
@@ -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,2 @@
1
+ require 'cog/native_extensions/string'
2
+ require 'cog/native_extensions/array'
@@ -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
@@ -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
@@ -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 an active spec fixture.
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', "#{name}")
75
+ File.expand_path File.join(active_fixture_dir, 'cog', 'templates', name.to_s)
72
76
  end
73
77
 
74
- # @param name [String] tool fixture identifier
75
- # @return [String] path to the test tool with the given name
76
- def tool(name)
77
- File.expand_path File.join(spec_root, 'tools', name.to_s, 'lib', "#{name}.rb")
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
- if File.exists?(path) && File.directory?(path)
93
- FileUtils.rm_rf active_fixture_dir if File.exists? active_fixture_dir
94
- FileUtils.cp_r path, active_fixture_dir
95
- Dir.chdir active_fixture_dir
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>] a list of lines to match against standard output
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 { "to [write|not write] #{x.join "\n"} to STDOUT"}
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
- lines.zip(x).all? {|a, b| a.strip == b.to_s.strip}
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
@@ -92,7 +92,7 @@ module Cog
92
92
 
93
93
  def _failure_message(repl)
94
94
  msg = instance_eval &@msg_block
95
- msg = msg.gsub /\[([^\|\]]*)(?:\|([^\]]*)\])?/, '\2'
95
+ msg = msg.gsub /\[([^\|\]]*)(?:\|([^\]]*)\])?/, repl
96
96
  "expected #{@invocation} #{msg}\n#{trace}"
97
97
  end
98
98
  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}, :tools => @tools)
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['COG_TOOLS'] = @tools
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
- "`COG_TOOLS=#{@tools} #{@cmd.compact.join ' '}`"
49
+ "`#{@cmd.compact.join ' '}`"
56
50
  end
57
51
  end
58
52
 
@@ -1,5 +1,5 @@
1
1
  module Cog
2
2
  unless const_defined? :VERSION
3
- VERSION = '0.2.2'
3
+ VERSION = '0.3.0'
4
4
  end
5
5
  end