cog 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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