code-tools 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/code-tools +4 -0
- data/bin/ender +153 -0
- data/bin/spacer +154 -0
- data/bin/vamper +180 -0
- data/lib/core_ext.rb +54 -0
- data/lib/spacer/csharp.rb +142 -0
- data/lib/spacer/text.rb +85 -0
- data/lib/spacer.rb +2 -0
- data/lib/vamper/default.version.config +105 -0
- data/lib/vamper/version_config_file.rb +42 -0
- data/lib/vamper/version_file.rb +97 -0
- data/lib/vamper.rb +3 -0
- metadata +102 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5bccd6fecbea6c93c32b92522d03fc000ebe403b
|
4
|
+
data.tar.gz: 927adb322732ca9f2f37cff0372d0f5c215810be
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 596b5fec512b56871f04ed48d2633fd567ba80efa53c7b2bb5732b92643d707e8b8dcf76651dcea097b3323a8b212f0f6957ace5fef32ea9a543c780b8b83bd1
|
7
|
+
data.tar.gz: e9335f94a397cc1333d31aa0bd3df41fb3aa282840f1e50c39f07bfd67091d600d25572c0db1e9e59a7a8f72b312b0d5c14c4b5fd44a904aba874aa1e053a80b
|
data/bin/code-tools
ADDED
data/bin/ender
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'methadone'
|
6
|
+
|
7
|
+
class Tool
|
8
|
+
include Methadone::Main
|
9
|
+
include Methadone::CLILogging
|
10
|
+
|
11
|
+
main do |input_file|
|
12
|
+
unless File.exist?(input_file)
|
13
|
+
error "File #{input_file} does not exist"
|
14
|
+
next 1
|
15
|
+
end
|
16
|
+
|
17
|
+
output_file = options[:output_file]
|
18
|
+
|
19
|
+
if output_file.nil?
|
20
|
+
output_file = input_file
|
21
|
+
end
|
22
|
+
|
23
|
+
# Read the entire file and determine all the different line endings
|
24
|
+
file_contents = IO.read(input_file)
|
25
|
+
num_cr = 0
|
26
|
+
num_lf = 0
|
27
|
+
num_crlf = 0
|
28
|
+
num_lines = 1
|
29
|
+
|
30
|
+
i = 0
|
31
|
+
while i < file_contents.length do
|
32
|
+
c = file_contents[i]
|
33
|
+
|
34
|
+
if c == "\r"
|
35
|
+
if i < file_contents.length - 1 and file_contents[i + 1] == "\n"
|
36
|
+
num_crlf += 1
|
37
|
+
i += 1
|
38
|
+
else
|
39
|
+
num_cr += 1
|
40
|
+
end
|
41
|
+
|
42
|
+
num_lines += 1
|
43
|
+
elsif c == "\n"
|
44
|
+
num_lf += 1
|
45
|
+
num_lines += 1
|
46
|
+
end
|
47
|
+
i += 1
|
48
|
+
end
|
49
|
+
|
50
|
+
num_endings = (num_cr > 0 ? 1 : 0) + (num_lf > 0 ? 1 : 0) + (num_crlf > 0 ? 1 : 0)
|
51
|
+
le = num_endings > 1 ? :mixed : num_cr > 0 ? :cr : num_lf > 0 ? :lf : :crlf
|
52
|
+
msg = "\"#{input_file}\", #{le.to_s}, #{num_lines} lines"
|
53
|
+
|
54
|
+
if options[:mode].nil?
|
55
|
+
info msg
|
56
|
+
next 1
|
57
|
+
end
|
58
|
+
|
59
|
+
if options[:mode] == :auto
|
60
|
+
# Find the most common line ending and make that the automatic line ending
|
61
|
+
auto_line_ending = :lf
|
62
|
+
n = num_lf
|
63
|
+
|
64
|
+
if num_crlf > n
|
65
|
+
auto_line_ending = :crlf
|
66
|
+
n = num_crlf
|
67
|
+
end
|
68
|
+
|
69
|
+
if num_cr > n
|
70
|
+
auto_line_ending = :cr
|
71
|
+
end
|
72
|
+
|
73
|
+
options[:mode] = auto_line_ending
|
74
|
+
end
|
75
|
+
|
76
|
+
new_num_lines = 1
|
77
|
+
|
78
|
+
if (options[:mode] == :cr and num_cr + 1 == num_lines) or
|
79
|
+
(options[:mode] == :lf and num_lf + 1 == num_lines) or
|
80
|
+
(options[:mode] == :crlf and num_crlf + 1 == num_lines)
|
81
|
+
# We're not changing the line endings; nothing to do
|
82
|
+
new_num_lines = num_lines
|
83
|
+
else
|
84
|
+
newline_chars =
|
85
|
+
options[:mode] == :cr ? "\r" :
|
86
|
+
options[:mode] == :lf ? "\n" :
|
87
|
+
"\r\n"
|
88
|
+
|
89
|
+
file = nil
|
90
|
+
|
91
|
+
begin
|
92
|
+
file = File.new(output_file, 'w')
|
93
|
+
|
94
|
+
i = 0
|
95
|
+
while i < file_contents.length
|
96
|
+
c = file_contents[i]
|
97
|
+
|
98
|
+
if c == "\r"
|
99
|
+
if i < file_contents.length - 1 && file_contents[i + 1] == "\n"
|
100
|
+
i += 1
|
101
|
+
end
|
102
|
+
|
103
|
+
new_num_lines += 1
|
104
|
+
file.write(newline_chars)
|
105
|
+
elsif c == "\n"
|
106
|
+
new_num_lines += 1
|
107
|
+
file.write(newline_chars)
|
108
|
+
else
|
109
|
+
file.write(c)
|
110
|
+
end
|
111
|
+
|
112
|
+
i += 1
|
113
|
+
end
|
114
|
+
rescue Exception => e
|
115
|
+
error "unable to write #{output_file}. #{e.to_s}"
|
116
|
+
next 1
|
117
|
+
ensure
|
118
|
+
file.close() unless !file
|
119
|
+
end
|
120
|
+
|
121
|
+
msg += " -> \"#{output_file}\", #{options[:mode].to_s}, #{new_num_lines} lines"
|
122
|
+
end
|
123
|
+
|
124
|
+
info msg
|
125
|
+
end
|
126
|
+
|
127
|
+
change_logger Methadone::CLILogger.new
|
128
|
+
|
129
|
+
description 'Ender - the line ending fixer'
|
130
|
+
version '5.0.0'
|
131
|
+
|
132
|
+
on("-o", "--output-file FILE", "The output file. Default is the same as the input file.")
|
133
|
+
on("-m", "--mode MODE",
|
134
|
+
"The convert mode, either auto, cr, lf, crlf. auto will use the most commonly occurring ending. "\
|
135
|
+
"Updates will only be done when this argument is given.") do |mode|
|
136
|
+
options[:mode] = case mode
|
137
|
+
when 'auto', 'a'
|
138
|
+
:auto
|
139
|
+
when 'lf'
|
140
|
+
:lf
|
141
|
+
when 'cr'
|
142
|
+
:cr
|
143
|
+
when 'crlf'
|
144
|
+
:crlf
|
145
|
+
else
|
146
|
+
exit_now! "Unknown mode #{mode}"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
arg :input_file, "Input file to check or convert"
|
151
|
+
|
152
|
+
go!
|
153
|
+
end
|
data/bin/spacer
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'methadone'
|
6
|
+
require 'spacer'
|
7
|
+
|
8
|
+
class Tool
|
9
|
+
include Methadone::Main
|
10
|
+
include Methadone::CLILogging
|
11
|
+
|
12
|
+
# When reporting the tool indicates beginning-of-line \(BOL\) tabs and spaces.
|
13
|
+
# When replacing, all tabs not at the beginning of a line are replaced with spaces.
|
14
|
+
# Spaces and tabs inside multi-line C# strings (@"...") and inside Ruby \%Q\(...\) strings
|
15
|
+
# are ignored.
|
16
|
+
# Note that conversion to tabs may still leave the file as mixed as some lines may have
|
17
|
+
# spaces that are not a whole number multiple of the tabstop size. In that case use the
|
18
|
+
# -round option to remove smooth out the spurious spaces.
|
19
|
+
|
20
|
+
def self.get_whitespace_type(bol)
|
21
|
+
(bol.tabs > 0) ? (bol.spaces > 0 ? :mixed : :tabs) : :spaces
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.read_file_lines(filename)
|
25
|
+
# Read the entire file
|
26
|
+
file_contents = File.read(filename)
|
27
|
+
|
28
|
+
# Convert to a list of lines, preserving the end-of-lines
|
29
|
+
lines = []
|
30
|
+
s = 0
|
31
|
+
i = 0
|
32
|
+
|
33
|
+
while i < file_contents.length do
|
34
|
+
c = file_contents[i]
|
35
|
+
c1 = i < file_contents.length - 1 ? file_contents[i + 1] : "\0"
|
36
|
+
|
37
|
+
if c == "\r"
|
38
|
+
i += 1
|
39
|
+
|
40
|
+
if c1 == "\n"
|
41
|
+
i += 1
|
42
|
+
end
|
43
|
+
elsif c == "\n"
|
44
|
+
i += 1
|
45
|
+
else
|
46
|
+
i += 1
|
47
|
+
next
|
48
|
+
end
|
49
|
+
|
50
|
+
lines.push(file_contents[s, i - s])
|
51
|
+
s = i
|
52
|
+
end
|
53
|
+
|
54
|
+
if s != i
|
55
|
+
lines.push(file_contents[s, i - s])
|
56
|
+
end
|
57
|
+
|
58
|
+
lines
|
59
|
+
end
|
60
|
+
|
61
|
+
main do |input_file|
|
62
|
+
unless File.exist?(input_file)
|
63
|
+
error "File #{input_file} does not exist"
|
64
|
+
next 1
|
65
|
+
end
|
66
|
+
|
67
|
+
output_file = options[:output_file]
|
68
|
+
|
69
|
+
if output_file.nil?
|
70
|
+
output_file = input_file
|
71
|
+
end
|
72
|
+
|
73
|
+
if File.extname(input_file) == '.cs'
|
74
|
+
file_type = :csharp
|
75
|
+
else
|
76
|
+
file_type = :text
|
77
|
+
end
|
78
|
+
|
79
|
+
lines = read_file_lines(input_file)
|
80
|
+
|
81
|
+
if file_type == :text
|
82
|
+
before = Spacer::Text.count_bol_spaces_and_tabs(lines)
|
83
|
+
else
|
84
|
+
before = Spacer::CSharp.count_bol_spaces_and_tabs(lines)
|
85
|
+
end
|
86
|
+
|
87
|
+
if !options[:mode].nil?
|
88
|
+
if file_type == :text
|
89
|
+
Spacer::Text.untabify(lines, options[:tabsize])
|
90
|
+
else
|
91
|
+
Spacer::CSharp.untabify(lines, options[:tabsize])
|
92
|
+
end
|
93
|
+
|
94
|
+
if options[:mode] == :tabs
|
95
|
+
if file_type == :text
|
96
|
+
Spacer::Text.tabify(lines, options[:tabsize], options[:round])
|
97
|
+
else
|
98
|
+
Spacer::CSharp.tabify(lines, options[:tabsize], options[:round])
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
msg = "\"#{input_file}\", #{file_type.to_s}, #{get_whitespace_type(before).to_s}"
|
104
|
+
|
105
|
+
if !options[:mode].nil?
|
106
|
+
if file_type == :text
|
107
|
+
after = Spacer::Text.count_bol_spaces_and_tabs(lines)
|
108
|
+
else
|
109
|
+
after = Spacer::CSharp.count_bol_spaces_and_tabs(lines)
|
110
|
+
end
|
111
|
+
|
112
|
+
file = nil
|
113
|
+
|
114
|
+
begin
|
115
|
+
file = File.new(output_file, 'w')
|
116
|
+
|
117
|
+
for line in lines do
|
118
|
+
file.write(line)
|
119
|
+
end
|
120
|
+
ensure
|
121
|
+
file.close() unless file == nil
|
122
|
+
end
|
123
|
+
|
124
|
+
msg += " -> \"#{output_file}\", #{get_whitespace_type(after).to_s}"
|
125
|
+
end
|
126
|
+
|
127
|
+
info msg
|
128
|
+
end
|
129
|
+
|
130
|
+
description 'Spacer - source file space/tab fixer tool'
|
131
|
+
version '5.0.0'
|
132
|
+
|
133
|
+
options[:tabsize] = 4
|
134
|
+
options[:round] = false
|
135
|
+
|
136
|
+
on("-o", "--output-file FILE", "The output file. Default is the same as the input file.")
|
137
|
+
on("-m", "--mode MODE","The convert mode (tabs or spaces) Default is to just display the files current state."\
|
138
|
+
"Updates will only be done when this argument is given.") do |mode|
|
139
|
+
options[:mode] = case mode
|
140
|
+
when 'tabs', 't'
|
141
|
+
:tabs
|
142
|
+
when 'spaces', 's'
|
143
|
+
:spaces
|
144
|
+
else
|
145
|
+
exit_now! "Unknown mode #{mode}"
|
146
|
+
end
|
147
|
+
end
|
148
|
+
on("-t", "--tabsize TABSIZE", "Tab size in spaces to assume. Default is #{options[:tabsize]} spaces.")
|
149
|
+
on("-r", "--round", "When tabifying, round BOL spaces down to an exact number of tabs.")
|
150
|
+
|
151
|
+
arg :input_file, "Input file to check or convert"
|
152
|
+
|
153
|
+
go!
|
154
|
+
end
|
data/bin/vamper
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'methadone'
|
6
|
+
require 'vamper'
|
7
|
+
require 'tzinfo'
|
8
|
+
|
9
|
+
class Tool
|
10
|
+
include Methadone::Main
|
11
|
+
include Methadone::CLILogging
|
12
|
+
|
13
|
+
def self.find_version_file()
|
14
|
+
dir = Dir.pwd
|
15
|
+
|
16
|
+
while dir.length != 0
|
17
|
+
files = Dir.glob('*.version')
|
18
|
+
if files.length > 0
|
19
|
+
file = files[0]
|
20
|
+
break
|
21
|
+
else
|
22
|
+
if dir == '/'
|
23
|
+
dir = ''
|
24
|
+
else
|
25
|
+
dir = File.expand_path('..', dir)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
if file.nil?
|
31
|
+
exit_now! 'Unable to find a .version file in this or parent directories.'
|
32
|
+
end
|
33
|
+
|
34
|
+
file
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.get_full_date(now)
|
38
|
+
now.year * 10000 + now.month * 100 + now.mday
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_jdate(now, start_year)
|
42
|
+
(((now.year - start_year + 1) * 10000) + (now.month * 100) + now.mday).to_s
|
43
|
+
end
|
44
|
+
|
45
|
+
main do |input_file|
|
46
|
+
if input_file.nil? or !File.exist?(input_file)
|
47
|
+
input_file = find_version_file
|
48
|
+
end
|
49
|
+
|
50
|
+
input_file = File.expand_path(input_file)
|
51
|
+
|
52
|
+
project_name = File.basename(input_file, '.version')
|
53
|
+
version_config_file_name = "#{File.dirname(input_file)}/#{project_name}.version.config"
|
54
|
+
|
55
|
+
info "Version file is '#{input_file}'"
|
56
|
+
info "Version config is '#{version_config_file_name}'"
|
57
|
+
info "Project name is '#{project_name}'"
|
58
|
+
|
59
|
+
if File.exists?(input_file)
|
60
|
+
version_data = Vamper::VersionFile.new(File.open(input_file))
|
61
|
+
else
|
62
|
+
version_data = Vamper::VersionFile.new
|
63
|
+
end
|
64
|
+
|
65
|
+
now = TZInfo::Timezone.get(version_data.time_zone).now
|
66
|
+
|
67
|
+
case version_data.build_value_type
|
68
|
+
when :JDate
|
69
|
+
build = get_jdate(now, version_data.start_year)
|
70
|
+
|
71
|
+
if version_data.build != build
|
72
|
+
version_data.revision = 0
|
73
|
+
version_data.build = build
|
74
|
+
else
|
75
|
+
version_data.revision += 1
|
76
|
+
end
|
77
|
+
when :Incremental
|
78
|
+
version_data.build += 1
|
79
|
+
version_data.revision = 0
|
80
|
+
else # :FullDate
|
81
|
+
build = get_full_date(now)
|
82
|
+
|
83
|
+
if version_data.build != build
|
84
|
+
version_data.revision = 0
|
85
|
+
version_data.build = build
|
86
|
+
else
|
87
|
+
version_data.revision += 1
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
tags = version_data.tags
|
92
|
+
|
93
|
+
case version_data.build_value_type
|
94
|
+
when :FullDate
|
95
|
+
build_str = build.to_s
|
96
|
+
tags[:DashBuild] = build_str[0..3] + '-' + build_str[4..5] + '-' + build_str[6..7]
|
97
|
+
end
|
98
|
+
|
99
|
+
info 'Version tags are:'
|
100
|
+
tags.each { |key, value|
|
101
|
+
info " #{key}=#{value}"
|
102
|
+
}
|
103
|
+
|
104
|
+
if options[:update]
|
105
|
+
info 'Updating version information:'
|
106
|
+
end
|
107
|
+
|
108
|
+
unless File.exists?(version_config_file_name)
|
109
|
+
FileUtils.cp(Vamper::VersionConfigFile.get_default_file, version_config_file_name)
|
110
|
+
end
|
111
|
+
|
112
|
+
version_config_file = Vamper::VersionConfigFile.new(File.open(version_config_file_name), tags)
|
113
|
+
file_list = version_data.files.map { |file_name| file_name.replace_tags!(tags) }
|
114
|
+
|
115
|
+
file_list.each do |file_name|
|
116
|
+
path = File.expand_path(File.join(File.dirname(input_file), file_name))
|
117
|
+
path_file_name = File.basename(path)
|
118
|
+
match = false
|
119
|
+
|
120
|
+
for file_type in version_config_file.file_types do
|
121
|
+
match = file_type.file_specs.any? { |file_spec| file_spec.match(path_file_name) }
|
122
|
+
unless match
|
123
|
+
next
|
124
|
+
end
|
125
|
+
|
126
|
+
if file_type.write
|
127
|
+
dir = File.dirname(path)
|
128
|
+
unless Dir.exists?(dir)
|
129
|
+
error "Directory '#{dir}' does not exist to write file ''#{path_file_name}''"
|
130
|
+
exit(1)
|
131
|
+
end
|
132
|
+
|
133
|
+
if options[:update]
|
134
|
+
IO.write(path, file_type.write)
|
135
|
+
end
|
136
|
+
else # !file_type.write
|
137
|
+
if File.exists?(path)
|
138
|
+
if options[:update]
|
139
|
+
file_type.updates.each do |update|
|
140
|
+
content = IO.read(path)
|
141
|
+
# At this point the only ${...} variables left in the replace strings are Before and After
|
142
|
+
# This line converts the ${...} into \k<...> to put captured groups from search back
|
143
|
+
# into the replace string.
|
144
|
+
content.gsub!(%r(#{update.search})m, update.replace.gsub(/\${(\w+)}/,'\\\\k<\\1>'))
|
145
|
+
IO.write(path, content)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
else
|
149
|
+
error "file #{path} does not exist to update"
|
150
|
+
exit(1)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
break
|
155
|
+
end
|
156
|
+
|
157
|
+
unless match
|
158
|
+
error "file '#{path}' has no matching file type in the .version.config"
|
159
|
+
exit(1)
|
160
|
+
end
|
161
|
+
|
162
|
+
info path
|
163
|
+
|
164
|
+
if options[:update]
|
165
|
+
version_data.write_to(File.open(input_file, 'w'))
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
description 'Vamper - file version stamper'
|
171
|
+
version '5.0.0'
|
172
|
+
|
173
|
+
options[:update] = false
|
174
|
+
|
175
|
+
on("-u", "--update", "Actually do the update.")
|
176
|
+
|
177
|
+
arg :input_file, "A version file. Default is to search parent directories for *.version", :optional
|
178
|
+
|
179
|
+
go!
|
180
|
+
end
|
data/lib/core_ext.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
class String
|
2
|
+
def underscore
|
3
|
+
self.gsub(/::/, '/').
|
4
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
5
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
6
|
+
tr('-', '_').
|
7
|
+
downcase
|
8
|
+
end
|
9
|
+
|
10
|
+
def replace_tags(tags)
|
11
|
+
str = self
|
12
|
+
tags.each { |name, value|
|
13
|
+
str = str.gsub(%r(\$\{#{name.to_s}\})m, value)
|
14
|
+
}
|
15
|
+
str
|
16
|
+
end
|
17
|
+
|
18
|
+
def replace_tags!(tags)
|
19
|
+
tags.each { |name, value|
|
20
|
+
self.gsub!(%r(\$\{#{name.to_s}\})m, value)
|
21
|
+
}
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
# colorization
|
26
|
+
def colorize(color_code)
|
27
|
+
"\e[#{color_code}m#{self}\e[0m"
|
28
|
+
end
|
29
|
+
|
30
|
+
def red
|
31
|
+
colorize(31)
|
32
|
+
end
|
33
|
+
|
34
|
+
def green
|
35
|
+
colorize(32)
|
36
|
+
end
|
37
|
+
|
38
|
+
def yellow
|
39
|
+
colorize(33)
|
40
|
+
end
|
41
|
+
|
42
|
+
def blue
|
43
|
+
colorize(34)
|
44
|
+
end
|
45
|
+
|
46
|
+
def pink
|
47
|
+
colorize(35)
|
48
|
+
end
|
49
|
+
|
50
|
+
def light_blue
|
51
|
+
colorize(36)
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module Spacer
|
4
|
+
module CSharp
|
5
|
+
def self.count_bol_spaces_and_tabs(lines)
|
6
|
+
bol = OpenStruct.new
|
7
|
+
bol.tabs = 0
|
8
|
+
bol.spaces = 0
|
9
|
+
in_multi_line_string = false
|
10
|
+
|
11
|
+
for line in lines do
|
12
|
+
in_bol = true
|
13
|
+
i = 0
|
14
|
+
while i < line.length do
|
15
|
+
c = line[i]
|
16
|
+
c1 = i < line.length - 1 ? line[i + 1] : "\0"
|
17
|
+
|
18
|
+
if in_multi_line_string and c == "\"" and c1 != "\""
|
19
|
+
in_multi_line_string = false
|
20
|
+
elsif c == "@" and c1 == "\""
|
21
|
+
in_multi_line_string = true
|
22
|
+
i += 1
|
23
|
+
elsif in_bol and !in_multi_line_string and c == " "
|
24
|
+
bol.spaces += 1
|
25
|
+
elsif in_bol and !in_multi_line_string and c == "\t"
|
26
|
+
bol.tabs += 1
|
27
|
+
else
|
28
|
+
in_bol = false
|
29
|
+
end
|
30
|
+
i += 1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
bol
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.untabify(lines, tabsize)
|
38
|
+
# Expand tabs anywhere on a line, but not inside @"..." strings
|
39
|
+
in_multi_line_string = false
|
40
|
+
|
41
|
+
i = 0
|
42
|
+
while i < lines.length do
|
43
|
+
line = lines[i]
|
44
|
+
in_string = false
|
45
|
+
new_line = ""
|
46
|
+
j = 0
|
47
|
+
|
48
|
+
while j < line.length do
|
49
|
+
c_1 = j > 0 ? line[j - 1] : '\0'
|
50
|
+
c = line[j]
|
51
|
+
c1 = j < line.length - 1 ? line[j + 1] : '\0'
|
52
|
+
|
53
|
+
raise "line #{i + 1} has overlapping regular and multiline strings" if (in_string and in_multi_line_string)
|
54
|
+
|
55
|
+
if !in_multi_line_string and c == "\t"
|
56
|
+
# Add spaces to next tabstop
|
57
|
+
num_spaces = tabsize - (new_line.length % tabsize)
|
58
|
+
|
59
|
+
new_line += " " * num_spaces
|
60
|
+
elsif !in_multi_line_string and !in_string and c == "\""
|
61
|
+
in_string = true
|
62
|
+
new_line += c
|
63
|
+
elsif !in_multi_line_string and !in_string and c == "@" and c1 == "\""
|
64
|
+
in_multi_line_string = true
|
65
|
+
new_line += c
|
66
|
+
j += 1
|
67
|
+
new_line += c1
|
68
|
+
elsif in_string and c == "\"" and c_1 != "\\"
|
69
|
+
in_string = false
|
70
|
+
new_line += c
|
71
|
+
elsif in_multi_line_string and c == "\"" and c1 != "\""
|
72
|
+
in_multi_line_string = false
|
73
|
+
new_line += c
|
74
|
+
else
|
75
|
+
new_line += c
|
76
|
+
end
|
77
|
+
|
78
|
+
lines[i] = new_line
|
79
|
+
j += 1
|
80
|
+
end
|
81
|
+
i += 1
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.tabify(lines, tabsize, round_down_spaces)
|
86
|
+
# Insert tabs for spaces, but only at the beginning of lines and not inside @"..." or "..." strings
|
87
|
+
in_multi_line_string = false
|
88
|
+
i = 0
|
89
|
+
|
90
|
+
while i < lines.length do
|
91
|
+
line = lines[i]
|
92
|
+
in_string = false
|
93
|
+
bol = true
|
94
|
+
num_bol_spaces = 0
|
95
|
+
new_line = ""
|
96
|
+
j = 0
|
97
|
+
|
98
|
+
while j < line.length do
|
99
|
+
c_1 = j > 0 ? line[j - 1] : "\0"
|
100
|
+
c = line[j]
|
101
|
+
c1 = j < line.length - 1 ? line[j + 1] : "\0"
|
102
|
+
|
103
|
+
if !in_string and !in_multi_line_string and bol and c == " "
|
104
|
+
# Just count the spaces
|
105
|
+
num_bol_spaces += 1
|
106
|
+
elsif !in_string and !in_multi_line_string and bol and c != " "
|
107
|
+
bol = false
|
108
|
+
|
109
|
+
new_line += "\t" * (num_bol_spaces / tabsize)
|
110
|
+
|
111
|
+
if !round_down_spaces
|
112
|
+
new_line += " " * (num_bol_spaces % tabsize)
|
113
|
+
end
|
114
|
+
# Process this character again as not BOL
|
115
|
+
j -= 1
|
116
|
+
elsif !in_multi_line_string and !in_string and c == '"'
|
117
|
+
in_string = true
|
118
|
+
new_line += c
|
119
|
+
elsif !in_multi_line_string and !in_string and c == "@" and c1 == "\""
|
120
|
+
in_multi_line_string = true
|
121
|
+
new_line += c
|
122
|
+
j += 1
|
123
|
+
new_line += c1
|
124
|
+
elsif in_string and c == "\"" and c_1 != "\\"
|
125
|
+
in_string = false
|
126
|
+
new_line += c
|
127
|
+
elsif in_multi_line_string and c == "\"" and c1 != "\""
|
128
|
+
in_multi_line_string = false
|
129
|
+
new_line += c
|
130
|
+
else
|
131
|
+
new_line += c
|
132
|
+
end
|
133
|
+
|
134
|
+
lines[i] = new_line
|
135
|
+
j += 1
|
136
|
+
end
|
137
|
+
i += 1
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
end
|
data/lib/spacer/text.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
module Spacer
|
2
|
+
module Text
|
3
|
+
def self.count_bol_spaces_and_tabs(lines)
|
4
|
+
bol = OpenStruct.new
|
5
|
+
bol.spaces = 0
|
6
|
+
bol.tabs = 0
|
7
|
+
|
8
|
+
for line in lines do
|
9
|
+
for i in 0...line.length do
|
10
|
+
c = line[i]
|
11
|
+
|
12
|
+
if c == " "
|
13
|
+
bol.spaces += 1
|
14
|
+
elsif c == "\t"
|
15
|
+
bol.tabs += 1
|
16
|
+
else
|
17
|
+
break
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
bol
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.untabify(lines, tabsize)
|
26
|
+
i = 0
|
27
|
+
while i < lines.length do
|
28
|
+
line = lines[i]
|
29
|
+
j = 0
|
30
|
+
new_line = ""
|
31
|
+
|
32
|
+
while j < line.length do
|
33
|
+
c = line[j]
|
34
|
+
|
35
|
+
if c == "\t"
|
36
|
+
num_spaces = tabsize - (new_line.length % tabsize)
|
37
|
+
new_line += " " * num_spaces
|
38
|
+
else
|
39
|
+
new_line += c
|
40
|
+
end
|
41
|
+
j += 1
|
42
|
+
end
|
43
|
+
|
44
|
+
lines[i] = new_line
|
45
|
+
i += 1
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.tabify(lines, tabsize, round_down_spaces)
|
50
|
+
i = 0
|
51
|
+
while i < lines.length do
|
52
|
+
line = lines[i]
|
53
|
+
j = 0
|
54
|
+
bol = true
|
55
|
+
num_bol_spaces = 0
|
56
|
+
new_line = ""
|
57
|
+
|
58
|
+
while j < line.length do
|
59
|
+
c = line[j]
|
60
|
+
|
61
|
+
if bol and c == " "
|
62
|
+
num_bol_spaces += 1
|
63
|
+
elsif bol and c != " "
|
64
|
+
bol = false
|
65
|
+
new_line += "\t" * (num_bol_spaces / tabsize)
|
66
|
+
|
67
|
+
if !round_down_spaces
|
68
|
+
new_line += " " * (num_bol_spaces % tabsize)
|
69
|
+
end
|
70
|
+
|
71
|
+
new_line += c
|
72
|
+
else
|
73
|
+
new_line += c
|
74
|
+
end
|
75
|
+
|
76
|
+
j += 1
|
77
|
+
end
|
78
|
+
|
79
|
+
lines[i] = new_line
|
80
|
+
i += 1
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
data/lib/spacer.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" ?>
|
2
|
+
<VersionConfig>
|
3
|
+
<FileType>
|
4
|
+
<Name>Ruby Files</Name>
|
5
|
+
<FileSpec>*.rb</FileSpec>
|
6
|
+
<Update>
|
7
|
+
<Search>(?'Before'\$VERSION=\')([0-9]+\.[0-9]+\.[0-9]+)-[0-9]+\.[0-9]+(?'After'\')</Search>
|
8
|
+
<Replace>${Before}${Major}.${Minor}.${Patch}-${Build}.${Revision}${After}</Replace>
|
9
|
+
</Update>
|
10
|
+
</FileType>
|
11
|
+
<FileType>
|
12
|
+
<Name>Version-in-a-text-file</Name>
|
13
|
+
<FileSpec>*.version.txt</FileSpec>
|
14
|
+
<Write>Release ${Major}.${Minor}.${Build}.${Revision}</Write>
|
15
|
+
</FileType>
|
16
|
+
<FileType>
|
17
|
+
<Name>Windows Manifest File</Name>
|
18
|
+
<FileSpec>WMManifest.xml</FileSpec>
|
19
|
+
<Update>
|
20
|
+
<Search>(?'Before'Version=")([0-9]+\.[0-9]+)(?'After'\.[0-9]+\.[0-9]+")</Search>
|
21
|
+
<Replace>${Before}${Major}.${Minor}${After}</Replace>
|
22
|
+
</Update>
|
23
|
+
</FileType>
|
24
|
+
<FileType>
|
25
|
+
<Name>C# Source</Name>
|
26
|
+
<FileSpec>*.cs</FileSpec>
|
27
|
+
<Update>
|
28
|
+
<Search>(?'Before'AssemblyVersion\(")([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(?'After'"\))</Search>
|
29
|
+
<Replace>${Before}${Major}.${Minor}.0.0${After}</Replace>
|
30
|
+
</Update>
|
31
|
+
<Update>
|
32
|
+
<Search>(?'Before'AssemblyFileVersion\(")([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(?'After'"\))</Search>
|
33
|
+
<Replace>${Before}${Major}.${Minor}.${Build}.${Revision}${After}</Replace>
|
34
|
+
</Update>
|
35
|
+
<Update>
|
36
|
+
<Search>(?'Before'AssemblyProduct\(")([^"]*)(?'After'"\))</Search>
|
37
|
+
<Replace>${Before}${Product}${After}</Replace>
|
38
|
+
</Update>
|
39
|
+
<Update>
|
40
|
+
<Search>(?'Before'AssemblyCopyright\(")([^"]*)(?'After'"\))</Search>
|
41
|
+
<Replace>${Before}${Copyright}${After}</Replace>
|
42
|
+
</Update>
|
43
|
+
<Update>
|
44
|
+
<Search>(?'Before'AssemblyCompany\(")([^"]*)(?'After'"\))</Search>
|
45
|
+
<Replace>${Before}${Company}${After}</Replace>
|
46
|
+
</Update>
|
47
|
+
</FileType>
|
48
|
+
<FileType>
|
49
|
+
<Name>Windows RC File</Name>
|
50
|
+
<FileSpec>*.rc</FileSpec>
|
51
|
+
<Update>
|
52
|
+
<Search>(?'Before'FILEVERSION )([0-9]+,[0-9]+,[0-9]+,[0-9]+)</Search>
|
53
|
+
<Replace>${Before}${Major},${Minor},${Build},${Revision}</Replace>
|
54
|
+
</Update>
|
55
|
+
<Update>
|
56
|
+
<Search>(?'Before'PRODUCTVERSION )([0-9]+,[0-9]+,[0-9]+,[0-9]+)</Search>
|
57
|
+
<Replace>${Before}${Major},${Minor},${Build},${Revision}</Replace>
|
58
|
+
</Update>
|
59
|
+
<Update>
|
60
|
+
<Search>(?'Before'"FileVersion",[ \t]*")([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(?'After'")</Search>
|
61
|
+
<Replace>${Before}${Major}.${Minor}.${Build}.${Revision}${After}</Replace>
|
62
|
+
</Update>
|
63
|
+
<Update>
|
64
|
+
<Search>(?'Before'"ProductVersion",[ \t]*")([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(?'After'")</Search>
|
65
|
+
<Replace>${Before}${Major}.${Minor}.${Build}.${Revision}${After}</Replace>
|
66
|
+
</Update>
|
67
|
+
</FileType>
|
68
|
+
<FileType>
|
69
|
+
<Name>WiX Files</Name>
|
70
|
+
<FileSpec>*.wxi</FileSpec>
|
71
|
+
<FileSpec>*.wxs</FileSpec>
|
72
|
+
<Update>
|
73
|
+
<Search>(?'Before'ProductVersion = ")([0-9]+\.[0-9]+)(?'After'")</Search>
|
74
|
+
<Replace>${Before}${Major}.${Minor}${After}</Replace>
|
75
|
+
</Update>
|
76
|
+
<Update>
|
77
|
+
<Search>(?'Before'ProductBuild = ")([0-9]+\.([0-9]|[1-9][0-9]))(?'After'")</Search>
|
78
|
+
<Replace>${Before}${Build}.${Revision}${After}</Replace>
|
79
|
+
</Update>
|
80
|
+
</FileType>
|
81
|
+
<FileType>
|
82
|
+
<Name>.NET Config Files</Name>
|
83
|
+
<FileSpec>*.config</FileSpec>
|
84
|
+
<Update>
|
85
|
+
<Search>(?'Before', +Version=)\d+\.\d+(?'After'\.0\.0 *,)</Search>
|
86
|
+
<Replace>${Before}${Major}.${Minor}${After}</Replace>
|
87
|
+
</Update>
|
88
|
+
</FileType>
|
89
|
+
<FileType>
|
90
|
+
<Name>Visual Studio Project Files</Name>
|
91
|
+
<FileSpec>*.csproj</FileSpec>
|
92
|
+
<Update>
|
93
|
+
<Search>(?'Before'<OutputName>" + projectName + @"_)([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(?'After'</OutputName>)</Search>
|
94
|
+
<Replace>${Before}${Major}.${Minor}.${Build}.${Revision}${After}</Replace>
|
95
|
+
</Update>
|
96
|
+
</FileType>
|
97
|
+
<FileType>
|
98
|
+
<Name>VSIX Manifest</Name>
|
99
|
+
<FileSpec>*.vsixmanifest</FileSpec>
|
100
|
+
<Update>
|
101
|
+
<Search>(?'Before'<Version>)([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)(?'After'</Version>)</Search>
|
102
|
+
<Replace>${Before}${Major}.${Minor}.${Build}.${Revision}${After}</Replace>
|
103
|
+
</Update>
|
104
|
+
</FileType>
|
105
|
+
</VersionConfig>
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require_relative '../core_ext.rb'
|
3
|
+
|
4
|
+
module Vamper
|
5
|
+
class VersionConfigFile
|
6
|
+
|
7
|
+
def self.get_default_file
|
8
|
+
File.join(File.dirname(__FILE__), 'default.version.config')
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(io, tags)
|
12
|
+
doc = Nokogiri::XML(io)
|
13
|
+
|
14
|
+
@file_types = []
|
15
|
+
doc.xpath('/VersionConfig/FileType').each do |node|
|
16
|
+
file_type_struct = Struct.new(:name, :file_specs, :updates, :write)
|
17
|
+
search_replace_struct = Struct.new(:search, :replace)
|
18
|
+
file_type = file_type_struct.new
|
19
|
+
file_type.name = node.name
|
20
|
+
file_type.file_specs = node.xpath('FileSpec').map { |sub_node|
|
21
|
+
Regexp.new('^' + Regexp::escape(sub_node.text).gsub('\\*', '.*').gsub('\\?', '.') + '$')
|
22
|
+
}
|
23
|
+
update_node_set = node.xpath('Update')
|
24
|
+
if update_node_set
|
25
|
+
# Replace ${...} entries in the replace string with equivalent tags if available
|
26
|
+
file_type.updates = update_node_set.map { |sub_node|
|
27
|
+
s_and_r = search_replace_struct.new(
|
28
|
+
%r(#{sub_node.at_xpath('Search').text.gsub(/\(\?'(\w+)'/, '(?<\\1>')}),
|
29
|
+
sub_node.at_xpath('Replace').text.replace_tags(tags))
|
30
|
+
}
|
31
|
+
end
|
32
|
+
write_node = node.at_xpath('Write')
|
33
|
+
if write_node
|
34
|
+
file_type.write = write_node.text.replace_tags(tags)
|
35
|
+
end
|
36
|
+
@file_types.push(file_type)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
attr_reader :file_types
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require_relative '../core_ext.rb'
|
3
|
+
|
4
|
+
module Vamper
|
5
|
+
class BadVersionFile < StandardError; end
|
6
|
+
|
7
|
+
class VersionFile
|
8
|
+
attr_reader :tags
|
9
|
+
|
10
|
+
def initialize(io)
|
11
|
+
if io
|
12
|
+
@doc = Nokogiri::XML(io, &:noblanks)
|
13
|
+
|
14
|
+
unless @doc.root.name == 'Version'
|
15
|
+
raise BadVersionFile, 'Root element must be Version'
|
16
|
+
end
|
17
|
+
else
|
18
|
+
@doc = Nokogiri::XML::Document.new
|
19
|
+
@doc.root.add_child(Nokogiri::XML::Element.new('Version', @doc))
|
20
|
+
end
|
21
|
+
|
22
|
+
add_attribute @doc.root, :BuildValueType => :JDate
|
23
|
+
add_child_list_element @doc.root, :Files, :Tags
|
24
|
+
add_child_element tags_element,
|
25
|
+
:Major => 1, :Minor => 0, :Build => 0, :Patch => 0, :Revision => 0, :TimeZone => 'UTC'
|
26
|
+
add_child_element tags_element, {:StartYear => TZInfo::Timezone.get(self.time_zone).now.year}
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_attribute(parent_node, attr_definitions)
|
30
|
+
attr_definitions.each { |attr_symbol, attr_default|
|
31
|
+
method_name = attr_symbol.to_s.underscore
|
32
|
+
unless parent_node[attr_symbol]
|
33
|
+
parent_node[attr_symbol] = attr_default
|
34
|
+
end
|
35
|
+
define_singleton_method(method_name.to_sym) {
|
36
|
+
parent_node[attr_symbol].to_sym
|
37
|
+
}
|
38
|
+
define_singleton_method((method_name + '=').to_sym) { |value|
|
39
|
+
parent_node[attr_symbol] = value.to_s
|
40
|
+
}
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
def add_child_list_element(parent_element, *element_symbols)
|
45
|
+
element_symbols.each { |element_symbol|
|
46
|
+
name = element_symbol.to_s
|
47
|
+
elem = parent_element.at(name)
|
48
|
+
unless elem
|
49
|
+
elem = parent_element.add_child(Nokogiri::XML::Element.new(name, @doc))
|
50
|
+
end
|
51
|
+
|
52
|
+
method_name = name.underscore + '_element'
|
53
|
+
define_singleton_method(method_name.to_sym) {
|
54
|
+
elem
|
55
|
+
}
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_child_element(parent_element, element_definitions)
|
60
|
+
element_definitions.each { |element_symbol, element_default|
|
61
|
+
name = element_symbol.to_s
|
62
|
+
elem = parent_element.at(name)
|
63
|
+
unless elem
|
64
|
+
elem = parent_element.add_child(Nokogiri::XML::Element.new(name, @doc))
|
65
|
+
elem.content = element_default.to_s
|
66
|
+
end
|
67
|
+
|
68
|
+
method_name = name.underscore
|
69
|
+
case element_default
|
70
|
+
when Fixnum
|
71
|
+
define_singleton_method(method_name.to_sym) {
|
72
|
+
Integer(elem.content)
|
73
|
+
}
|
74
|
+
when String
|
75
|
+
define_singleton_method(method_name.to_sym) {
|
76
|
+
elem.content.to_s
|
77
|
+
}
|
78
|
+
end
|
79
|
+
define_singleton_method((method_name + '=').to_sym) { |value|
|
80
|
+
elem.content = value.to_s
|
81
|
+
}
|
82
|
+
}
|
83
|
+
end
|
84
|
+
|
85
|
+
def write_to(io)
|
86
|
+
@doc.write_xml_to(io, :indent_text => ' ', :indent => 2)
|
87
|
+
end
|
88
|
+
|
89
|
+
def tags
|
90
|
+
Hash[tags_element.children.select {|node| node.name != 'text'}.map {|node| [node.name.to_sym, node.content]}]
|
91
|
+
end
|
92
|
+
def files
|
93
|
+
files_element.children.select {|node| node.name != 'text'}.map {|node| node.content}
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
data/lib/vamper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: code-tools
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 5.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- John Lyon-smith
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-01-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: tzinfo
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: nokogiri
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.6'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: methadone
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.9'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.9'
|
55
|
+
description: Tools for source code maintenance, including version stamping, line endings
|
56
|
+
and tab/space conversion.
|
57
|
+
email: john@jamoki.com
|
58
|
+
executables:
|
59
|
+
- code-tools
|
60
|
+
- ender
|
61
|
+
- spacer
|
62
|
+
- vamper
|
63
|
+
extensions: []
|
64
|
+
extra_rdoc_files: []
|
65
|
+
files:
|
66
|
+
- bin/code-tools
|
67
|
+
- bin/ender
|
68
|
+
- bin/spacer
|
69
|
+
- bin/vamper
|
70
|
+
- lib/core_ext.rb
|
71
|
+
- lib/spacer.rb
|
72
|
+
- lib/spacer/csharp.rb
|
73
|
+
- lib/spacer/text.rb
|
74
|
+
- lib/vamper.rb
|
75
|
+
- lib/vamper/default.version.config
|
76
|
+
- lib/vamper/version_config_file.rb
|
77
|
+
- lib/vamper/version_file.rb
|
78
|
+
homepage: http://rubygems.org/gems/code_tools
|
79
|
+
licenses:
|
80
|
+
- MIT
|
81
|
+
metadata: {}
|
82
|
+
post_install_message:
|
83
|
+
rdoc_options: []
|
84
|
+
require_paths:
|
85
|
+
- lib
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - "~>"
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '2.0'
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
requirements: []
|
97
|
+
rubyforge_project:
|
98
|
+
rubygems_version: 2.4.5
|
99
|
+
signing_key:
|
100
|
+
specification_version: 4
|
101
|
+
summary: Source code tools
|
102
|
+
test_files: []
|