cog 0.2.0 → 0.2.1
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/bin/cog +1 -1
- data/lib/cog.rb +1 -1
- data/lib/cog/config/cogfile.rb +22 -1
- data/lib/cog/embeds.rb +89 -0
- data/lib/cog/embeds/context.rb +86 -0
- data/lib/cog/{project.rb → embeds/file_scanner.rb} +7 -77
- data/lib/cog/errors.rb +1 -1
- data/lib/cog/generator.rb +8 -7
- data/lib/cog/version.rb +1 -1
- metadata +7 -5
data/bin/cog
CHANGED
@@ -73,7 +73,7 @@ command [:generator, :gen] do |c|
|
|
73
73
|
c.command :run do |sub|
|
74
74
|
sub.action do |gopt, opt, args|
|
75
75
|
raise Cog::Errors::ActionRequiresProject.new('run generator') unless Cog::Config.instance.project?
|
76
|
-
Cog::
|
76
|
+
Cog::Embeds.gather_from_project
|
77
77
|
args = Cog::Controllers::GeneratorController.list if args.empty?
|
78
78
|
args.each do |name|
|
79
79
|
Cog::Controllers::GeneratorController.run name
|
data/lib/cog.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'cog/config'
|
2
2
|
require 'cog/controllers'
|
3
|
+
require 'cog/embeds'
|
3
4
|
require 'cog/errors'
|
4
5
|
require 'cog/generator'
|
5
6
|
require 'cog/helpers'
|
6
7
|
require 'cog/languages'
|
7
|
-
require 'cog/project'
|
8
8
|
require 'cog/version'
|
9
9
|
|
10
10
|
# +cog+ is a command line utility that makes it a bit easier to organize a project
|
data/lib/cog/config/cogfile.rb
CHANGED
@@ -10,10 +10,31 @@ module Cog
|
|
10
10
|
# +Cogfile+ files are used to configure an instance of {Config}.
|
11
11
|
#
|
12
12
|
# @example
|
13
|
+
# # All paths are relative to the directory containing this file.
|
14
|
+
#
|
15
|
+
# # Define the directory in which to find project generators
|
13
16
|
# project_generators_path 'cog/generators'
|
17
|
+
#
|
18
|
+
# # Define the directory in which to find custom project templates
|
14
19
|
# project_templates_path 'cog/templates'
|
20
|
+
#
|
21
|
+
# # Define the directory to which project source code is generated
|
15
22
|
# project_source_path 'src'
|
16
|
-
#
|
23
|
+
#
|
24
|
+
# # Explicitly specify a mapping from file extensions to languages
|
25
|
+
# #
|
26
|
+
# # key => value pairs from this mapping will override the default
|
27
|
+
# # language map supplied by +cog+
|
28
|
+
# #
|
29
|
+
# # Type `cog language list` to see a list of supported languages
|
30
|
+
# # and the current file extension mappings
|
31
|
+
# language_extensions({
|
32
|
+
# # :h => 'c++',
|
33
|
+
# })
|
34
|
+
#
|
35
|
+
# # Define the target language which should be used when
|
36
|
+
# # creating generators, and no language is explicitly specified
|
37
|
+
# default_target_language 'c++'
|
17
38
|
#
|
18
39
|
class Cogfile
|
19
40
|
|
data/lib/cog/embeds.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'cog/config'
|
2
|
+
require 'cog/embeds/context'
|
3
|
+
require 'cog/embeds/file_scanner'
|
4
|
+
|
5
|
+
module Cog
|
6
|
+
|
7
|
+
# Methods for querying and manipulating project files
|
8
|
+
module Embeds
|
9
|
+
|
10
|
+
# Search through all project files for cog embeds, and remember them so that generators can refer to them later
|
11
|
+
def gather_from_project
|
12
|
+
@embeds ||= {}
|
13
|
+
@embed_pattern ||= "cog\\s*:\\s*([-A-Za-z0-9_.]+)\\s*(?:\\(\\s*(.+?)\\s*\\))?(\\s*once\\s*)?(\\s*\\{)?"
|
14
|
+
exts = Config.instance.language_summary.collect(&:extensions).flatten
|
15
|
+
sources = Dir.glob "#{Config.instance.project_source_path}/**/*.{#{exts.join ','}}"
|
16
|
+
sources.each do |filename|
|
17
|
+
ext = File.extname(filename).slice(1..-1)
|
18
|
+
lang = Config.instance.language_for_extension ext
|
19
|
+
w = File.read filename
|
20
|
+
w.scan(lang.comment_pattern(@embed_pattern)) do |m|
|
21
|
+
key = m[0].split.first
|
22
|
+
@embeds[key] ||= {}
|
23
|
+
@embeds[key][filename] ||= 0
|
24
|
+
@embeds[key][filename] += 1
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# @param key [String] embed key for which to find directive occurrences
|
30
|
+
# @yieldparam filename [String] name of the file in which the embed occurred
|
31
|
+
# @yieldparam index [Fixnum] occurrence index of the embed, 0 for the first occurrence, 1 for the second, and so on
|
32
|
+
def find(key)
|
33
|
+
x = @embeds[key]
|
34
|
+
unless x.nil?
|
35
|
+
x.keys.sort.each do |filename|
|
36
|
+
x[filename].times do |index|
|
37
|
+
yield filename, index
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# @param key [String] unique identifier for the embed
|
44
|
+
# @param filename [String] file in which to look for the embed
|
45
|
+
# @param index [Fixnum] occurrence of the embed. 0 for first, 1 for second, ...
|
46
|
+
# @yieldparam context [Context] describes the context in which the directive occurred
|
47
|
+
# @yieldreturn [String] the value to substitute into the embed expansion
|
48
|
+
# @return [Boolean] whether or not the expansion was updated
|
49
|
+
def update(key, filename, index, &block)
|
50
|
+
c = Context.new key, filename
|
51
|
+
snip_pattern = c.language.comment_pattern("cog\\s*:\\s*(#{key})\\s*(?:\\(\\s*(.+?)\\s*\\))?(\\s*once\\s*)?(?:\\s*([{]))?")
|
52
|
+
end_pattern = c.language.comment_pattern("cog\\s*:\\s*[}]")
|
53
|
+
not_end_pattern = c.language.comment_pattern("cog\\s*:\\s*(?!\\s*[}]).*$")
|
54
|
+
|
55
|
+
s = FileScanner.new filename
|
56
|
+
updated = if match = s.read_until(snip_pattern, index)
|
57
|
+
if match.nil? # embed not found
|
58
|
+
false
|
59
|
+
else
|
60
|
+
c.lineno = s.marked_line_number
|
61
|
+
c.args = match[2].split if match[2]
|
62
|
+
c.once = !match[3].nil?
|
63
|
+
if match[4] == '{' # embed already expanded
|
64
|
+
unless s.capture_until end_pattern, :but_not => not_end_pattern
|
65
|
+
raise Errors::SnippetExpansionUnterminated.new "#{filename.relative_to_project_root}:#{s.marked_line_number}"
|
66
|
+
end
|
67
|
+
c.body = s.captured_text
|
68
|
+
value = block.call(c).rstrip
|
69
|
+
if c.once? || value != s.captured_text
|
70
|
+
s.replace_captured_text(value + "\n", :once => c.once?)
|
71
|
+
end
|
72
|
+
else # embed not yet expanded
|
73
|
+
value = block.call(c).rstrip
|
74
|
+
snip_line = c.language.comment "#{c.to_directive} {"
|
75
|
+
unless c.once?
|
76
|
+
value = [snip_line, value, c.language.comment("cog: }")].join("\n")
|
77
|
+
end
|
78
|
+
s.insert_at_mark(value + "\n")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
s.close
|
83
|
+
updated
|
84
|
+
end
|
85
|
+
|
86
|
+
extend self # Singleton
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'cog/config'
|
2
|
+
|
3
|
+
module Cog
|
4
|
+
module Embeds
|
5
|
+
|
6
|
+
# Describes the environment of an embed statement including the file in which it was found, the line number, the language, an more.
|
7
|
+
class Context
|
8
|
+
|
9
|
+
# @return [Fixnum] line number at which the directive was found
|
10
|
+
attr_accessor :lineno
|
11
|
+
|
12
|
+
# @return [String] the value for the given key
|
13
|
+
attr_reader :name
|
14
|
+
|
15
|
+
# @param path [String] path to the file in which the cog directive was found
|
16
|
+
def initialize(name, path)
|
17
|
+
@name = name
|
18
|
+
@options = {}
|
19
|
+
@path = path
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [Array<String>] arguments passed to the directive
|
23
|
+
def args
|
24
|
+
@args
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [String] for block directives, the body of text which occurs between the curly braces.
|
28
|
+
# @example
|
29
|
+
# // cog: snippet(my-snip) {
|
30
|
+
# body
|
31
|
+
# // cog: }
|
32
|
+
def body
|
33
|
+
@body
|
34
|
+
end
|
35
|
+
|
36
|
+
# @return [String] the filename extension
|
37
|
+
def extension
|
38
|
+
@ext ||= File.extname(filename).slice(1..-1)
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [String] basename of the file in which the cog directive was found
|
42
|
+
def filename
|
43
|
+
@filename ||= File.basename @path
|
44
|
+
end
|
45
|
+
|
46
|
+
# @return [Languages::Language] the language of the file
|
47
|
+
def language
|
48
|
+
@lang ||= Config.instance.language_for_extension extension
|
49
|
+
end
|
50
|
+
|
51
|
+
# @return [Boolean] was the once switch used?
|
52
|
+
def once?
|
53
|
+
@once
|
54
|
+
end
|
55
|
+
|
56
|
+
# @api developer
|
57
|
+
# @param value [String, nil] set the body to this value
|
58
|
+
def body=(value)
|
59
|
+
@body = value
|
60
|
+
end
|
61
|
+
|
62
|
+
# @api developer
|
63
|
+
# @param value [Boolean] was the once switch used?
|
64
|
+
def once=(value)
|
65
|
+
@once = !!value
|
66
|
+
end
|
67
|
+
|
68
|
+
# @api developer
|
69
|
+
# @param value [Array<String>] arguments used with the directive
|
70
|
+
def args=(value)
|
71
|
+
@args = value
|
72
|
+
end
|
73
|
+
|
74
|
+
# @api developer
|
75
|
+
# @return [String]
|
76
|
+
def to_directive
|
77
|
+
x = "cog: #{name}"
|
78
|
+
x += args.join ' ' if args
|
79
|
+
x += " once" if once?
|
80
|
+
x
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
@@ -1,77 +1,7 @@
|
|
1
|
-
require 'cog/config'
|
2
|
-
|
3
1
|
module Cog
|
4
|
-
|
5
|
-
# Methods for querying and manipulating project files
|
6
|
-
module Project
|
2
|
+
module Embeds
|
7
3
|
|
8
|
-
#
|
9
|
-
def gather_cog_directives
|
10
|
-
@snippets ||= {}
|
11
|
-
@snippet_pattern ||= "cog\\s*:\\s*snippet\\s*\\(\\s*(.*?)\\s*\\)(\\s*\\{)?"
|
12
|
-
exts = Config.instance.language_summary.collect(&:extensions).flatten
|
13
|
-
sources = Dir.glob "#{Config.instance.project_source_path}/**/*.{#{exts.join ','}}"
|
14
|
-
sources.each do |filename|
|
15
|
-
ext = File.extname(filename).slice(1..-1)
|
16
|
-
lang = Config.instance.language_for_extension ext
|
17
|
-
w = File.read filename
|
18
|
-
w.scan(lang.comment_pattern(@snippet_pattern)) do |m|
|
19
|
-
key = m[0]
|
20
|
-
@snippets[key] ||= {}
|
21
|
-
@snippets[key][filename] ||= 0
|
22
|
-
@snippets[key][filename] += 1
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
# @param key [String] snippet key for which to find directive occurrences
|
28
|
-
# @yieldparam filename [String] name of the file in which the snippet occurred
|
29
|
-
# @yieldparam index [Fixnum] occurrence index of the snippet, 0 for the first occurrence, 1 for the second, and so on
|
30
|
-
def snippet_directives(key)
|
31
|
-
x = @snippets[key]
|
32
|
-
unless x.nil?
|
33
|
-
x.keys.sort.each do |filename|
|
34
|
-
x[filename].times do |index|
|
35
|
-
yield filename, index
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
# @param key [String] unique identifier for the snippet
|
42
|
-
# @param filename [String] file in which to look for the snippet
|
43
|
-
# @param index [Fixnum] occurrence of the snippet. 0 for first, 1 for second, ...
|
44
|
-
# @param value [String] expansion value to use as the update
|
45
|
-
# @return [Boolean] whether or not the expansion was updated
|
46
|
-
def update_snippet_expansion(key, filename, index, value)
|
47
|
-
value = value.rstrip
|
48
|
-
ext = File.extname(filename).slice(1..-1)
|
49
|
-
lang = Config.instance.language_for_extension ext
|
50
|
-
|
51
|
-
snip_pattern = lang.comment_pattern("cog\\s*:\\s*snippet\\s*\\(\\s*(#{key})\\s*\\)(?:\\s*([{]))?")
|
52
|
-
end_pattern = lang.comment_pattern("cog\\s*:\\s*[}]")
|
53
|
-
not_end_pattern = lang.comment_pattern("cog\\s*:\\s*(?!\\s*[}]).*$")
|
54
|
-
|
55
|
-
s = FileScanner.new filename
|
56
|
-
updated = if match = s.read_until(snip_pattern, index)
|
57
|
-
if match.nil? # snippet not found
|
58
|
-
false
|
59
|
-
elsif match[2] == '{' # snippet already expanded
|
60
|
-
unless s.capture_until end_pattern, :but_not => not_end_pattern
|
61
|
-
raise Errors::SnippetExpansionUnterminated.new "#{filename.relative_to_project_root}:#{s.marked_line_number}"
|
62
|
-
end
|
63
|
-
s.replace_captured_text(value + "\n") if value != s.captured_text
|
64
|
-
else # snippet not yet expanded
|
65
|
-
snip_line = lang.comment "cog: snippet(#{match[1]}) {"
|
66
|
-
value = [snip_line, value, lang.comment("cog: }") + "\n"]
|
67
|
-
s.insert_at_mark value.join("\n")
|
68
|
-
end
|
69
|
-
end
|
70
|
-
s.close
|
71
|
-
updated
|
72
|
-
end
|
73
|
-
|
74
|
-
# Helper for scanning files for snippet expansions
|
4
|
+
# Helper for scanning files for embed expansions
|
75
5
|
class FileScanner
|
76
6
|
|
77
7
|
def initialize(filename)
|
@@ -92,7 +22,7 @@ module Cog
|
|
92
22
|
# @return [nil]
|
93
23
|
def mark!
|
94
24
|
@mark = @f.pos
|
95
|
-
@marked_line_number = @f.lineno
|
25
|
+
@marked_line_number = @f.lineno + 1
|
96
26
|
end
|
97
27
|
|
98
28
|
def unmark!
|
@@ -161,13 +91,15 @@ module Cog
|
|
161
91
|
end
|
162
92
|
|
163
93
|
# @param value [String] value to replace the captured_text with
|
94
|
+
# @param opt [Boolean] :once (false) if once, the cog delimiters will be removed
|
164
95
|
# @return [Boolean] whether or not the operation succeeded
|
165
|
-
def replace_captured_text(value)
|
96
|
+
def replace_captured_text(value, opt={})
|
166
97
|
return false if @cap_begin_pos.nil? || @cap_end_pos.nil?
|
167
98
|
@f.seek 0
|
168
|
-
tmp.write @f.read(@cap_begin_pos)
|
99
|
+
tmp.write @f.read(opt[:once] ? @mark : @cap_begin_pos)
|
169
100
|
tmp.write value
|
170
101
|
@f.seek @cap_end_pos
|
102
|
+
@f.readline if opt[:once]
|
171
103
|
tmp.write @f.read
|
172
104
|
tmp.close
|
173
105
|
close
|
@@ -201,7 +133,5 @@ module Cog
|
|
201
133
|
end
|
202
134
|
end
|
203
135
|
|
204
|
-
extend self # Singleton
|
205
136
|
end
|
206
|
-
|
207
137
|
end
|
data/lib/cog/errors.rb
CHANGED
data/lib/cog/generator.rb
CHANGED
@@ -72,14 +72,15 @@ module Cog
|
|
72
72
|
nil
|
73
73
|
end
|
74
74
|
|
75
|
-
# Provide a value for the
|
76
|
-
# @param key [String] a unique identifier for the
|
77
|
-
# @
|
75
|
+
# Provide a value for the embed with the given key
|
76
|
+
# @param key [String] a unique identifier for the embed
|
77
|
+
# @yieldparam context [Embeds::Context] provides information about the environment in which the embed statement was found
|
78
|
+
# @yieldreturn The value which will be used to expand the embed (or replace the embedded content)
|
78
79
|
# @return [nil]
|
79
|
-
def
|
80
|
-
|
81
|
-
if
|
82
|
-
STDOUT.write "Updated #{filename.relative_to_project_root} - #{(index + 1).ordinalize} occurrence of
|
80
|
+
def embed(key, &block)
|
81
|
+
Embeds.find(key) do |filename, index|
|
82
|
+
if Embeds.update key, filename, index, &block
|
83
|
+
STDOUT.write "Updated #{filename.relative_to_project_root} - #{(index + 1).ordinalize} occurrence of embed '#{key}'\n".color :white
|
83
84
|
end
|
84
85
|
end
|
85
86
|
end
|
data/lib/cog/version.rb
CHANGED
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: 21
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 1
|
10
|
+
version: 0.2.1
|
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-12-
|
18
|
+
date: 2012-12-12 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: gli
|
@@ -146,6 +146,9 @@ files:
|
|
146
146
|
- lib/cog/controllers/template_controller.rb
|
147
147
|
- lib/cog/controllers/tool_controller.rb
|
148
148
|
- lib/cog/controllers.rb
|
149
|
+
- lib/cog/embeds/context.rb
|
150
|
+
- lib/cog/embeds/file_scanner.rb
|
151
|
+
- lib/cog/embeds.rb
|
149
152
|
- lib/cog/errors.rb
|
150
153
|
- lib/cog/generator/file_methods.rb
|
151
154
|
- lib/cog/generator/filters.rb
|
@@ -165,7 +168,6 @@ files:
|
|
165
168
|
- lib/cog/languages/qt_project_language.rb
|
166
169
|
- lib/cog/languages/ruby_language.rb
|
167
170
|
- lib/cog/languages.rb
|
168
|
-
- lib/cog/project.rb
|
169
171
|
- lib/cog/spec_helpers/matchers/match_maker.rb
|
170
172
|
- lib/cog/spec_helpers/matchers.rb
|
171
173
|
- lib/cog/spec_helpers/runner.rb
|