i18n-tools 0.0.2
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/MIT-LICENSE +20 -0
- data/README.textile +1 -0
- data/bin/i18n-keys +6 -0
- data/lib/ansi.rb +19 -0
- data/lib/i18n/keys.rb +51 -0
- data/lib/i18n/keys/commands.rb +53 -0
- data/lib/i18n/keys/formatter.rb +39 -0
- data/lib/i18n/keys/index.rb +209 -0
- data/lib/i18n/keys/occurence.rb +120 -0
- data/lib/i18n/parser/erb_parser.rb +54 -0
- data/lib/i18n/parser/ruby_parser.rb +93 -0
- data/test/all.rb +1 -0
- data/test/commands_test.rb +1 -0
- data/test/erb_parser_test.rb +14 -0
- data/test/fixtures/source_1.rb +14 -0
- data/test/fixtures/source_2.rb +1 -0
- data/test/fixtures/template.html.erb +19 -0
- data/test/index_test.rb +135 -0
- data/test/keys_test.rb +75 -0
- data/test/occurence_test.rb +130 -0
- data/test/ruby_parser_test.rb +54 -0
- data/test/test_helper.rb +14 -0
- metadata +84 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Sven Fuchs <svenfuchs@artweb-design.de>
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
to turn off filename generation in zsh: unsetopt GLOB
|
data/bin/i18n-keys
ADDED
data/lib/ansi.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Ansi
|
2
|
+
COLORS = { :red =>";31", :yellow => ";33", :green => ";32" }
|
3
|
+
STYLES = { :bold => ";1", :underline => ";4" }
|
4
|
+
|
5
|
+
def ansi_format(text, formats)
|
6
|
+
res = "\e[0"
|
7
|
+
if formats.is_a?(Array) || formats.is_a?(Hash)
|
8
|
+
COLORS.each { |k,v| res += v if formats.include?(k) }
|
9
|
+
STYLES.each { |k,v| res += v if formats.include?(k) }
|
10
|
+
elsif formats.is_a?(Symbol)
|
11
|
+
COLORS.each { |k,v| res += v if formats == k }
|
12
|
+
STYLES.each { |k,v| res += v if formats == k }
|
13
|
+
elsif formats.respond_to?(:to_sym)
|
14
|
+
COLORS.each { |k,v| res += v if formats.to_sym == k }
|
15
|
+
STYLES.each { |k,v| res += v if formats.to_sym == k }
|
16
|
+
end
|
17
|
+
res += "m" + text.to_s + "\e[0m"
|
18
|
+
end
|
19
|
+
end
|
data/lib/i18n/keys.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/parser/ruby_parser'
|
2
|
+
require File.dirname(__FILE__) + '/parser/erb_parser'
|
3
|
+
require File.dirname(__FILE__) + '/keys/index'
|
4
|
+
|
5
|
+
module I18n
|
6
|
+
module Keys
|
7
|
+
VERSION = '0.0.1'
|
8
|
+
|
9
|
+
@@root = '.'
|
10
|
+
@@verbose = true
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def verbose?
|
14
|
+
@@verbose
|
15
|
+
end
|
16
|
+
|
17
|
+
def verbose=(verbose)
|
18
|
+
@@verbose = !!verbose
|
19
|
+
end
|
20
|
+
|
21
|
+
def root
|
22
|
+
@@root
|
23
|
+
end
|
24
|
+
|
25
|
+
def root=(dir)
|
26
|
+
@@root = dir
|
27
|
+
end
|
28
|
+
|
29
|
+
def meta_dir
|
30
|
+
dir = root + '/.i18n'
|
31
|
+
FileUtils.mkdir(dir) unless File.exists?(dir)
|
32
|
+
dir
|
33
|
+
end
|
34
|
+
|
35
|
+
def config
|
36
|
+
@config ||= YAML.load_file(meta_dir + '/config.yml') rescue { 'indices' => {} }
|
37
|
+
end
|
38
|
+
|
39
|
+
def config=(config)
|
40
|
+
@config = config
|
41
|
+
end
|
42
|
+
|
43
|
+
def index(*args)
|
44
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
45
|
+
name = args.first || options.delete(:index)
|
46
|
+
index = Index.load_or_create_or_init(name, options)
|
47
|
+
index
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
program :version, I18n::Keys::VERSION
|
2
|
+
program :description, 'ruby i18n tools'
|
3
|
+
|
4
|
+
command :find do |c|
|
5
|
+
c.syntax = 'i18n find [key] --index --verbose'
|
6
|
+
c.summary = 'Find keys passed to I18n.t()'
|
7
|
+
c.example 'i18n find', 'i18n find foo bar --index'
|
8
|
+
c.option '--index', 'Use an index'
|
9
|
+
c.option '--verbose', 'Output information about index build'
|
10
|
+
c.when_called do |args, options|
|
11
|
+
I18n::Keys.verbose = options.verbose
|
12
|
+
index = I18n::Keys.index(:index => options.index)
|
13
|
+
index.each(*args.map { |arg| arg.dup }) { |occurence| puts occurence.to_s }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
command :replace do |c|
|
18
|
+
c.syntax = 'i18n replace [key] [replacement] --index --verbose'
|
19
|
+
c.summary = 'Replace keys passed to I18n.t() by something else'
|
20
|
+
c.example 'i18n replace', 'i18n replace foo bar --index'
|
21
|
+
c.option '--index', 'Use an index'
|
22
|
+
c.option '--verbose', 'Output information about index build'
|
23
|
+
c.when_called do |args, options|
|
24
|
+
search, replacement = args.shift, args.shift
|
25
|
+
raise Commander::Runner::InvalidCommandError.new('Wrong number of arguments') unless search && replacement
|
26
|
+
I18n::Keys.verbose = options.verbose
|
27
|
+
index = I18n::Keys.index(:index => options.index)
|
28
|
+
index.each(search.dup, replacement.dup) do |occurence|
|
29
|
+
index.replace(occurence, replacement) if I18n::Commands.replace?(occurence, replacement)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module I18n
|
35
|
+
module Commands
|
36
|
+
class << self
|
37
|
+
def replace?(occurence, replacement)
|
38
|
+
return true if @all
|
39
|
+
answer = I18n::Commands.confirm_replacement(occurence, replacement)[0, 1]
|
40
|
+
answer == 'a' ? @all = true : answer == 'y'
|
41
|
+
end
|
42
|
+
|
43
|
+
def confirm_replacement(occurence, replacement)
|
44
|
+
puts occurence.to_s, occurence.context
|
45
|
+
msg = "Replace this occurence of the key \"#{occurence.key}\" with \"#{replacement}\"? [Y]es [N]o [A]ll"
|
46
|
+
answer = ask(msg, %w(y yes n no a all)) do |q|
|
47
|
+
q.case = :downcase
|
48
|
+
q.readline = true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module I18n
|
2
|
+
module Keys
|
3
|
+
class Index
|
4
|
+
module Formatter
|
5
|
+
module Setup
|
6
|
+
def setup(target)
|
7
|
+
(class << target; self; end).send(:include, self)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module Stdin
|
12
|
+
extend Setup
|
13
|
+
|
14
|
+
def build(*args)
|
15
|
+
puts "building index \"#{name}\"" if I18n::Keys.verbose?
|
16
|
+
super
|
17
|
+
puts "\nfound #{occurences.size} occurences of #{keys.size} keys in #{files.size} files" if I18n::Keys.verbose?
|
18
|
+
end
|
19
|
+
|
20
|
+
def save
|
21
|
+
puts "saving index \"#{name}\"" if I18n::Keys.verbose?
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
def parse(file)
|
26
|
+
# puts " parsing #{file}" if I18n::Keys.verbose?
|
27
|
+
putc '.' if I18n::Keys.verbose?
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
# def each(*keys)
|
32
|
+
# puts "iterating occurences of: #{keys.map { |key| key.to_sym.inspect }.join(', ')}" if I18n::Keys.verbose?
|
33
|
+
# super
|
34
|
+
# end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require File.dirname(__FILE__) + '/formatter'
|
3
|
+
require File.dirname(__FILE__) + '/occurence'
|
4
|
+
|
5
|
+
# Keys.index(:default, :pattern => '/**/*.{rb,erb}').each(:foo, :bar) { |occurence| ... }
|
6
|
+
#
|
7
|
+
# when the :index name is not given it creates the index on the fly but won't save it
|
8
|
+
# when the :index name is true it uses :default as an index name
|
9
|
+
#
|
10
|
+
# when an index with the given name does not exist it builds and saves an index
|
11
|
+
# when an index with the given name exists and the given pattern does not match
|
12
|
+
# the index's pattern it issues a warning and rebuilds the index
|
13
|
+
#
|
14
|
+
# when no keys are given, occurences of all keys will be iterated
|
15
|
+
# when keys are given, only occurences of the given keys will be iterated
|
16
|
+
|
17
|
+
module I18n
|
18
|
+
module Keys
|
19
|
+
class Index
|
20
|
+
include Enumerable
|
21
|
+
|
22
|
+
@@formatter = Formatter::Stdin
|
23
|
+
@@default_pattern = '/**/*.{rb,erb}'
|
24
|
+
|
25
|
+
class << self
|
26
|
+
def load_or_create_or_init(*args)
|
27
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
28
|
+
name = TrueClass === args.first ? :default : args.first
|
29
|
+
index = name ? load_or_create(name, options) : new(name, options)
|
30
|
+
index
|
31
|
+
end
|
32
|
+
|
33
|
+
def load_or_create(*args)
|
34
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
35
|
+
name = args.first || :default
|
36
|
+
exists?(name) ? load(name) : create(name, options)
|
37
|
+
end
|
38
|
+
|
39
|
+
def create(*args)
|
40
|
+
index = new(*args)
|
41
|
+
index.update
|
42
|
+
index
|
43
|
+
end
|
44
|
+
|
45
|
+
def load(name)
|
46
|
+
File.open(filename(name), 'r') { |f| Marshal.load(f) } if exists?
|
47
|
+
end
|
48
|
+
|
49
|
+
def mk_dir
|
50
|
+
FileUtils.mkdir_p(store_dir) unless exists?
|
51
|
+
end
|
52
|
+
|
53
|
+
def exists?(name = nil)
|
54
|
+
name ? File.exists?(filename(name)) : File.exists?(store_dir)
|
55
|
+
end
|
56
|
+
|
57
|
+
def delete(name)
|
58
|
+
new(name).delete
|
59
|
+
end
|
60
|
+
|
61
|
+
def delete_all
|
62
|
+
FileUtils.rm_r(store_dir) if exists? rescue Errno::ENOENT
|
63
|
+
end
|
64
|
+
|
65
|
+
def filename(name)
|
66
|
+
store_dir + "/#{name.to_s}.marshal"
|
67
|
+
end
|
68
|
+
|
69
|
+
def store_dir
|
70
|
+
File.expand_path(Keys.meta_dir + '/indizes')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
attr_reader :name
|
75
|
+
|
76
|
+
[:keys, :occurences, :by_key].each do |name|
|
77
|
+
class_eval <<-code
|
78
|
+
def #{name} # def key
|
79
|
+
build unless built? # build unless built?
|
80
|
+
@#{name} # @key
|
81
|
+
end # end
|
82
|
+
code
|
83
|
+
end
|
84
|
+
|
85
|
+
def initialize(*args)
|
86
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
87
|
+
@name = args.first || :default
|
88
|
+
@pattern = options[:pattern] || @@default_pattern
|
89
|
+
reset!
|
90
|
+
@@formatter.setup(self) if @@formatter
|
91
|
+
end
|
92
|
+
|
93
|
+
def reset!
|
94
|
+
@built = false
|
95
|
+
@keys = []
|
96
|
+
@occurences = []
|
97
|
+
@by_key = {}
|
98
|
+
end
|
99
|
+
|
100
|
+
def built?
|
101
|
+
@built
|
102
|
+
end
|
103
|
+
|
104
|
+
def build(options = {})
|
105
|
+
@occurences = find_occurences(options)
|
106
|
+
@occurences.each do |occurence|
|
107
|
+
@keys << occurence.key
|
108
|
+
(@by_key[occurence.key] ||= []) << occurence
|
109
|
+
end
|
110
|
+
@built = true
|
111
|
+
end
|
112
|
+
|
113
|
+
def exists?
|
114
|
+
File.exists?(filename)
|
115
|
+
end
|
116
|
+
|
117
|
+
def save
|
118
|
+
self.class.mk_dir
|
119
|
+
File.open(filename, 'w+') { |f| Marshal.dump(self, f) }
|
120
|
+
end
|
121
|
+
|
122
|
+
def update(options = {})
|
123
|
+
reset!
|
124
|
+
build(options)
|
125
|
+
save
|
126
|
+
end
|
127
|
+
|
128
|
+
def delete
|
129
|
+
FileUtils.rm(filename) if exists? rescue Errno::ENOENT
|
130
|
+
end
|
131
|
+
|
132
|
+
def filename
|
133
|
+
self.class.filename(name)
|
134
|
+
end
|
135
|
+
|
136
|
+
def files
|
137
|
+
Dir[Keys.root + pattern]
|
138
|
+
end
|
139
|
+
|
140
|
+
def pattern
|
141
|
+
@pattern ||= config['pattern'] || @@default_pattern
|
142
|
+
end
|
143
|
+
|
144
|
+
def config
|
145
|
+
@config ||= Keys.config['indices'][name] || { }
|
146
|
+
end
|
147
|
+
|
148
|
+
def each(*keys)
|
149
|
+
patterns = key_patterns(keys)
|
150
|
+
occurences.each { |occurence| yield(occurence) if key_matches?(occurence.key, patterns) }
|
151
|
+
end
|
152
|
+
|
153
|
+
def inject(memo, *keys)
|
154
|
+
each(*keys) { |occurence| yield(memo, occurence) }
|
155
|
+
memo
|
156
|
+
end
|
157
|
+
|
158
|
+
def replace!(occurence, replacement)
|
159
|
+
occurence.replace!(replacement)
|
160
|
+
save if exists?
|
161
|
+
end
|
162
|
+
|
163
|
+
def marshal_dump
|
164
|
+
keys = :name, :pattern, :keys, :occurences, :by_key
|
165
|
+
keys.inject({ :built => built? }) { |result, key| result[key] = send(key); result }
|
166
|
+
end
|
167
|
+
|
168
|
+
def marshal_load(data)
|
169
|
+
keys = :name, :pattern, :keys, :occurences, :by_key, :built
|
170
|
+
keys.each { |key| instance_variable_set(:"@#{key}", data[key]) }
|
171
|
+
end
|
172
|
+
|
173
|
+
protected
|
174
|
+
|
175
|
+
def find_occurences(options)
|
176
|
+
files.inject([]) do |result, file|
|
177
|
+
calls = parse(file).find_by_type(:call).select { |call| call[2] == :t }
|
178
|
+
calls.inject(result) do |result, node|
|
179
|
+
node.each_key_node { |key| result << Occurence.from_sexp(key, file) }
|
180
|
+
result
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def key_matches?(subject, key_patterns)
|
186
|
+
key_patterns.empty? || key_patterns.any? do |key, pattern|
|
187
|
+
subject.to_sym == key || subject.to_s =~ pattern
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def key_patterns(keys)
|
192
|
+
keys.inject({}) { |result, key| result[key] = key_pattern(key); result }
|
193
|
+
end
|
194
|
+
|
195
|
+
def key_pattern(key)
|
196
|
+
key = key.to_s.dup
|
197
|
+
match_end = key.gsub!(/\*$/, '') ? '' : '$'
|
198
|
+
pattern = Regexp.escape("#{key}")
|
199
|
+
/^#{pattern}#{match_end}/
|
200
|
+
end
|
201
|
+
|
202
|
+
def parse(file)
|
203
|
+
source = File.read(file)
|
204
|
+
source = ErbParser.new.to_ruby(source) if File.extname(file) == '.erb'
|
205
|
+
RubyParser.new.parse(source)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../ansi'
|
2
|
+
|
3
|
+
module I18n
|
4
|
+
module Keys
|
5
|
+
class Occurence
|
6
|
+
include Ansi
|
7
|
+
|
8
|
+
@@context_lines = 2
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def context_lines
|
12
|
+
@@context_lines
|
13
|
+
end
|
14
|
+
|
15
|
+
def context_lines=(num)
|
16
|
+
@@context_lines = num
|
17
|
+
end
|
18
|
+
|
19
|
+
def from_sexp(sexp, file = nil)
|
20
|
+
new(sexp[1], file || sexp.file, sexp.source_start_pos, sexp.source_end_pos)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
attr_reader :key, :file, :start_pos, :end_pos
|
25
|
+
|
26
|
+
def initialize(key, file, start_pos, end_pos)
|
27
|
+
@key = key.to_sym
|
28
|
+
@file = file
|
29
|
+
@start_pos = start_pos
|
30
|
+
@end_pos = end_pos
|
31
|
+
end
|
32
|
+
|
33
|
+
def replace!(replacement)
|
34
|
+
replacement = replacement.to_sym.inspect
|
35
|
+
content = content_head + replacement + content_tail
|
36
|
+
@key = replacement.to_sym
|
37
|
+
self.length = replacement.to_s.length
|
38
|
+
File.open(file, 'w+') { |f| f.write(content) }
|
39
|
+
@position, @lines, @context = nil, nil, nil
|
40
|
+
end
|
41
|
+
|
42
|
+
def content
|
43
|
+
lines.join
|
44
|
+
end
|
45
|
+
|
46
|
+
def lines
|
47
|
+
@lines ||= File.open(file, 'r') { |f| f.readlines }
|
48
|
+
end
|
49
|
+
|
50
|
+
def line(highlight = false)
|
51
|
+
line = lines[line_num - 1].dup
|
52
|
+
highlight ? line_head + ansi_format(original_key, [:red, :bold]) + line_tail : line
|
53
|
+
end
|
54
|
+
|
55
|
+
def line_num
|
56
|
+
position[0]
|
57
|
+
end
|
58
|
+
|
59
|
+
def column
|
60
|
+
position[1]
|
61
|
+
end
|
62
|
+
|
63
|
+
def length
|
64
|
+
end_pos - start_pos + 1
|
65
|
+
end
|
66
|
+
|
67
|
+
def length=(length)
|
68
|
+
@length = length
|
69
|
+
@end_pos = start_pos + length - 1
|
70
|
+
end
|
71
|
+
|
72
|
+
def original_key
|
73
|
+
line[column - 1, length]
|
74
|
+
end
|
75
|
+
|
76
|
+
def content_head
|
77
|
+
content[0..(start_pos - 1)].to_s
|
78
|
+
end
|
79
|
+
|
80
|
+
def content_tail
|
81
|
+
content[(end_pos + 1)..-1].to_s
|
82
|
+
end
|
83
|
+
|
84
|
+
def line_head
|
85
|
+
line[0..(column - 2)].to_s
|
86
|
+
end
|
87
|
+
|
88
|
+
def line_tail
|
89
|
+
line[(column + length - 1)..-1].to_s
|
90
|
+
end
|
91
|
+
|
92
|
+
def context
|
93
|
+
@context ||=
|
94
|
+
lines[line_num - self.class.context_lines - 1, self.class.context_lines].join +
|
95
|
+
line(true) + lines[line_num, self.class.context_lines].join
|
96
|
+
end
|
97
|
+
|
98
|
+
def to_s
|
99
|
+
"#{key}: #{file} [#{line_num}/#{column}]"
|
100
|
+
end
|
101
|
+
|
102
|
+
def ==(other)
|
103
|
+
key == other.key and start_pos == other.start_pos and end_pos == other.end_pos
|
104
|
+
end
|
105
|
+
|
106
|
+
def position
|
107
|
+
@position ||= begin
|
108
|
+
line_num, col = 1, 1
|
109
|
+
lines.inject(0) do |sum, line|
|
110
|
+
break if sum + line.length > start_pos
|
111
|
+
line_num += 1
|
112
|
+
col = start_pos - sum - line.length + 1
|
113
|
+
sum += line.length
|
114
|
+
end
|
115
|
+
[line_num, col]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# replaces html and erb tags with whitespace so that we can parse the result
|
2
|
+
# as pure ruby preserving the exact positions of tokens in the original erb
|
3
|
+
# source code
|
4
|
+
|
5
|
+
require 'erb'
|
6
|
+
$KCODE = 'u'
|
7
|
+
|
8
|
+
class String
|
9
|
+
def to_whitespace
|
10
|
+
gsub(/\S/, ' ')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module I18n
|
15
|
+
class ErbParser
|
16
|
+
class Scanner < ERB::Compiler::Scanner
|
17
|
+
def scan
|
18
|
+
stag_reg = /(.*?)(^[ \t]*<%-|<%%|<%=|<%#|<%-|<%|\z)/m
|
19
|
+
etag_reg = /(.*?)(%%>|-%>|%>|\z)/m
|
20
|
+
scanner = StringScanner.new(@src)
|
21
|
+
while !scanner.eos?
|
22
|
+
scanner.scan(@stag ? etag_reg : stag_reg)
|
23
|
+
yield(scanner[1]) unless scanner[1].nil?
|
24
|
+
yield(scanner[2]) unless scanner[2].nil?
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
ERB::Compiler::Scanner.regist_scanner(Scanner, nil, false)
|
29
|
+
|
30
|
+
def to_ruby(source)
|
31
|
+
result = ''
|
32
|
+
comment = false
|
33
|
+
scanner = ERB::Compiler.new(nil).make_scanner(source)
|
34
|
+
scanner.scan do |token|
|
35
|
+
comment = true if token == '<%#'
|
36
|
+
if scanner.stag.nil?
|
37
|
+
result << token.to_whitespace
|
38
|
+
scanner.stag = token if ['<%', '<%-', '<%=', '<%#', "\n"].include?(token)
|
39
|
+
elsif ['%>', '-%>'].include?(token)
|
40
|
+
result << token.to_whitespace
|
41
|
+
scanner.stag = nil
|
42
|
+
else
|
43
|
+
result << (comment ? token.to_whitespace : token) # so, this is the ruby code, then
|
44
|
+
comment = false
|
45
|
+
end
|
46
|
+
end
|
47
|
+
result
|
48
|
+
end
|
49
|
+
|
50
|
+
def content_dump(string)
|
51
|
+
string.split("\n").map { |s| s.to_whitespace }.join("\n")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sexp_processor'
|
3
|
+
require 'ruby_parser'
|
4
|
+
|
5
|
+
# monkey patch galore, adds the ability to inspect the original source code
|
6
|
+
# that a :lit or :str sexp was parsed from
|
7
|
+
|
8
|
+
Sexp.class_eval do
|
9
|
+
attr_accessor :full_source, :source_start_pos, :source_end_pos
|
10
|
+
|
11
|
+
def value
|
12
|
+
self[1]
|
13
|
+
end
|
14
|
+
|
15
|
+
def source_range
|
16
|
+
source_start_pos..source_end_pos if source_start_pos && source_end_pos
|
17
|
+
end
|
18
|
+
|
19
|
+
def source
|
20
|
+
full_source[source_range] if full_source && source_range
|
21
|
+
end
|
22
|
+
|
23
|
+
def find_by_type(type)
|
24
|
+
nodes = []
|
25
|
+
nodes << self if self.first == type
|
26
|
+
each_of_type(type) { |node| nodes << node }
|
27
|
+
nodes
|
28
|
+
end
|
29
|
+
|
30
|
+
def each_key_node(&block)
|
31
|
+
each do |element|
|
32
|
+
next unless Sexp === element
|
33
|
+
element.each_key_node(&block)
|
34
|
+
block.call(element) if element.is_key_node?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def is_key_node?
|
39
|
+
first == :str || first == :lit && self[1].is_a?(Symbol)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
RubyLexer.class_eval do
|
44
|
+
attr_accessor :source_start_pos, :source_end_pos
|
45
|
+
|
46
|
+
def reset_source_positions!
|
47
|
+
self.source_start_pos, self.source_end_pos = nil, nil, nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
module I18n
|
52
|
+
class RubyParser < RubyParser
|
53
|
+
def s(*args)
|
54
|
+
result = super
|
55
|
+
|
56
|
+
result.full_source = lexer.src.string.dup
|
57
|
+
result.source_start_pos = lexer.source_start_pos
|
58
|
+
result.source_end_pos = lexer.source_end_pos || lexer.src.pos
|
59
|
+
lexer.reset_source_positions!
|
60
|
+
|
61
|
+
result
|
62
|
+
end
|
63
|
+
|
64
|
+
# :tSYMBOL
|
65
|
+
def _reduce_380(val, _values, result)
|
66
|
+
lexer.source_start_pos = lexer.src.pos - lexer.yacc_value.size - 1
|
67
|
+
lexer.source_end_pos = lexer.src.pos - 1
|
68
|
+
super
|
69
|
+
end
|
70
|
+
|
71
|
+
# :tSTRING
|
72
|
+
def _reduce_386(val, _values, result)
|
73
|
+
lexer.source_start_pos = lexer.src.pos - lexer.yacc_value.size - 2
|
74
|
+
lexer.source_end_pos = lexer.src.pos - 1
|
75
|
+
super
|
76
|
+
end
|
77
|
+
|
78
|
+
# :tSYMBEG
|
79
|
+
def _reduce_403(val, _values, result)
|
80
|
+
lexer.source_start_pos = lexer.src.pos - lexer.yacc_value.size - 2
|
81
|
+
super
|
82
|
+
end
|
83
|
+
|
84
|
+
def _reduce_418(val, _values, result)
|
85
|
+
result = super
|
86
|
+
result.source_start_pos = val[1].source_start_pos
|
87
|
+
result.source_end_pos = val[1].source_end_pos
|
88
|
+
result.full_source = val[1].full_source
|
89
|
+
result
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
data/test/all.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Dir[File.dirname(__FILE__) + '/*_test.rb'].each { |file| require file }
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
require 'erb'
|
3
|
+
|
4
|
+
class ErbParserTest < Test::Unit::TestCase
|
5
|
+
def test_sexp_filename
|
6
|
+
erb = File.read("#{File.dirname(__FILE__)}/fixtures/template.html.erb")
|
7
|
+
ruby = I18n::ErbParser.new.to_ruby(erb)
|
8
|
+
assert_equal erb.length, ruby.length
|
9
|
+
%w(erb_1 erb_2 foo.erb_3).each do |key|
|
10
|
+
assert ruby.index(key)
|
11
|
+
assert_equal erb.index(key), ruby.index(key)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
t(:bar_2)
|
data/test/index_test.rb
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class IndexTest < Test::Unit::TestCase
|
4
|
+
include I18n
|
5
|
+
|
6
|
+
def setup
|
7
|
+
I18n::Keys.verbose = false
|
8
|
+
@filenames = %W( #{File.dirname(__FILE__)}/fixtures/source_1.rb
|
9
|
+
#{File.dirname(__FILE__)}/fixtures/source_2.rb )
|
10
|
+
@default_keys_root, Keys.root = Keys.root, File.expand_path(File.dirname(__FILE__)) + '/fixtures'
|
11
|
+
FileUtils.cp(@filenames[0], "#{@filenames[0]}.backup")
|
12
|
+
end
|
13
|
+
|
14
|
+
def teardown
|
15
|
+
Keys::Index.delete_all
|
16
|
+
Keys.root = @default_keys_root
|
17
|
+
FileUtils.mv("#{@filenames[0]}.backup", @filenames[0])
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_index_default_pattern
|
21
|
+
Keys.config = nil
|
22
|
+
assert_equal '/**/*.{rb,erb}', Keys::Index.new.pattern
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_index_finds_files
|
26
|
+
expected = %w(test/fixtures/source_1.rb test/fixtures/source_2.rb).map { |p| File.expand_path(p) }
|
27
|
+
assert_equal expected, Keys::Index.new.files & expected
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_occurences_built_lazily_on_a_fresh_index
|
31
|
+
index = Keys::Index.new(:default)
|
32
|
+
expected = [:bar, :baaar, :baar, :bar, :bar_1, :bar_2]
|
33
|
+
assert_equal expected, index.occurences.select { |key| expected.include?(key.key) }.map(&:key)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_occurences_from_marshalled_index
|
37
|
+
index = Keys::Index.new(:marshalled)
|
38
|
+
index.update
|
39
|
+
index = Keys::Index.load(:marshalled)
|
40
|
+
expected = [:bar, :baaar, :baar, :bar, :bar_1, :bar_2]
|
41
|
+
assert_equal expected, index.occurences.select { |key| expected.include?(key.key) }.map(&:key)
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_index_create_builds_and_saves_the_index
|
45
|
+
index = Keys::Index.new(:create)
|
46
|
+
assert !index.exists?
|
47
|
+
index = Keys::Index.create(:create, :pattern => '/**/*.{rb}')
|
48
|
+
assert index.built?
|
49
|
+
assert index.exists?
|
50
|
+
assert_equal '/**/*.{rb}', index.pattern
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_index_load_or_create_creates_an_index
|
54
|
+
index = Keys::Index.load_or_create(:load_or_create, :pattern => '/**/*.{rb}')
|
55
|
+
assert index.exists?
|
56
|
+
assert_equal '/**/*.{rb}', index.pattern
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_index_load_or_create_or_init_with_no_name_given_does_not_save_the_index
|
60
|
+
index = Keys::Index.load_or_create_or_init(:pattern => '/**/*.{rb}')
|
61
|
+
assert !index.exists?
|
62
|
+
assert_equal '/**/*.{rb}', index.pattern
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_index_load_or_create_or_init_with_true_given_saves_the_default_index
|
66
|
+
index = Keys::Index.load_or_create_or_init(true, :pattern => '/**/*.{rb}')
|
67
|
+
assert index.exists?
|
68
|
+
assert_equal :default, index.name
|
69
|
+
assert_equal '/**/*.{rb}', index.pattern
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_index_load_or_create_or_init_with_name_given_saves_the_named_index
|
73
|
+
index = Keys::Index.load_or_create_or_init(:foo, :pattern => '/**/*.{rb}')
|
74
|
+
assert index.exists?
|
75
|
+
assert_equal :foo, index.name
|
76
|
+
assert_equal '/**/*.{rb}', index.pattern
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_index_exists_is_true_when_index_directory_exists
|
80
|
+
index = Keys::Index.create('foo')
|
81
|
+
assert index.exists?
|
82
|
+
FileUtils.rm_r(index.filename)
|
83
|
+
assert !index.exists?
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_index_inject_with_no_keys_given_iterates_over_all_occurences
|
87
|
+
index = Keys::Index.new(:pattern => '/**/*.{rb}')
|
88
|
+
expected = [:bar, :baaar, :baar, :'foo.bar', :bar, :bar_1, :bar_2]
|
89
|
+
result = index.inject([]) { |result, occurence| result << occurence.key }
|
90
|
+
assert_equal expected, result
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_index_inject_with_keys_given_iterates_over_occurences_of_given_keys
|
94
|
+
index = Keys::Index.new(:pattern => '/**/*.{rb}')
|
95
|
+
expected = [:bar, :baaar, :baar, :bar]
|
96
|
+
result = index.inject([], :bar, :baaar, :baar) { |result, occurence| result << occurence.key }
|
97
|
+
assert_equal expected, result
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_key_included_with_no_keys_given_returns_true
|
101
|
+
index = Keys::Index.new
|
102
|
+
assert index.send(:key_matches?, :foo, [])
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_key_included_with_the_key_included_returns_true
|
106
|
+
index = Keys::Index.new
|
107
|
+
assert index.send(:key_matches?, :foo, { :foo => /^foo$/, :bar => /^bar$/ })
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_key_pattern_with_no_wild_cards_returns_a_pattern_matching_only_the_key
|
111
|
+
index = Keys::Index.new
|
112
|
+
assert_equal /^foo\.bar$/, index.send(:key_pattern, :'foo.bar')
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_key_pattern_with_a_dot_separated_wild_card_at_the_end_returns_a_pattern_matching_all_keys_starting_with_key
|
116
|
+
index = Keys::Index.new
|
117
|
+
assert_equal /^foo\.bar\./, index.send(:key_pattern, :'foo.bar.*')
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_replace_replaces_key_without_wildcard_in_source_file
|
121
|
+
index = Keys::Index.create(:replace)
|
122
|
+
bar = index.by_key[:bar].first
|
123
|
+
index.replace!(bar, 'foo')
|
124
|
+
assert_equal " t(:foo)\n", bar.line
|
125
|
+
|
126
|
+
index = Keys::Index.load(:replace)
|
127
|
+
foo = index.by_key[:bar].first
|
128
|
+
assert foo == bar
|
129
|
+
end
|
130
|
+
|
131
|
+
# TODO
|
132
|
+
# - after replace make sure the index is updated
|
133
|
+
# - somehow also update the yaml/rb files
|
134
|
+
|
135
|
+
end
|
data/test/keys_test.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class KeysTest < Test::Unit::TestCase
|
4
|
+
include I18n
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@filenames = %W( #{File.dirname(__FILE__)}/fixtures/source_1.rb
|
8
|
+
#{File.dirname(__FILE__)}/fixtures/source_2.rb )
|
9
|
+
@default_keys_root, Keys.root = Keys.root, File.expand_path(File.dirname(__FILE__))
|
10
|
+
end
|
11
|
+
|
12
|
+
def teardown
|
13
|
+
Keys::Index.delete_all
|
14
|
+
Keys.root = @default_keys_root
|
15
|
+
Keys.config = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_root_defaults_to_dot
|
19
|
+
assert_equal '.', @default_keys_root
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_can_set_root
|
23
|
+
old_root = I18n::Keys.root
|
24
|
+
assert_nothing_raised { I18n::Keys.root = 'path/to/root' }
|
25
|
+
assert_equal 'path/to/root', I18n::Keys.root
|
26
|
+
I18n::Keys.root = old_root
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_index_given_no_name_returns_an_unbuilt_and_unsaved_index
|
30
|
+
index = Keys.index
|
31
|
+
assert_equal Keys::Index, index.class
|
32
|
+
assert !index.built?
|
33
|
+
assert !index.exists?
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_index_given_true_as_a_name_returns_the_built_default_index
|
37
|
+
index = Keys.index(true)
|
38
|
+
assert_equal Keys::Index, index.class
|
39
|
+
assert_equal :default, index.name
|
40
|
+
assert index.built?
|
41
|
+
assert index.exists?
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_index_given_a_regular_name_returns_the_built_named_index
|
45
|
+
index = Keys.index(:foo)
|
46
|
+
assert_equal Keys::Index, index.class
|
47
|
+
assert_equal :foo, index.name
|
48
|
+
assert index.built?
|
49
|
+
assert index.exists?
|
50
|
+
end
|
51
|
+
|
52
|
+
# def test_find_all_in_file
|
53
|
+
# expected = [:bar, :baaar, :baar, "bar", "bar_1"]
|
54
|
+
# keys = I18n::Keys.find(:files => @filenames[0])
|
55
|
+
# assert_equal expected, keys.select { |key| expected.include?(key.key) }.map(&:key)
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
# def test_find_all_in_files
|
59
|
+
# expected = ['bar_1', :bar_2]
|
60
|
+
# keys = I18n::Keys.find(:files => @filenames)
|
61
|
+
# assert_equal expected, keys.select { |key| expected.include?(key.key) }.map(&:key)
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
# def test_find_key_in_file
|
65
|
+
# expected = [:bar]
|
66
|
+
# keys = I18n::Keys.find(:keys => :bar, :files => @filenames[0])
|
67
|
+
# assert_equal expected, keys.select { |key| expected.include?(key.key) }.map(&:key)
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
# def test_find_key_in_files
|
71
|
+
# expected = [:bar]
|
72
|
+
# keys = I18n::Keys.find(:keys => :bar, :files => @filenames)
|
73
|
+
# assert_equal expected, keys.select { |key| expected.include?(key.key) }.map(&:key)
|
74
|
+
# end
|
75
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class OccurenceTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
I18n::Keys.verbose = false
|
6
|
+
end
|
7
|
+
|
8
|
+
def setup
|
9
|
+
I18n::Keys.verbose = false
|
10
|
+
@filename = "#{File.dirname(__FILE__)}/fixtures/source_1.rb"
|
11
|
+
FileUtils.cp(@filename, "#{@filename}.backup")
|
12
|
+
end
|
13
|
+
|
14
|
+
def teardown
|
15
|
+
FileUtils.mv("#{@filename}.backup", @filename)
|
16
|
+
end
|
17
|
+
|
18
|
+
def occurence(key = :bar)
|
19
|
+
index = I18n::Keys::Index.new
|
20
|
+
index.update
|
21
|
+
index.by_key[key.to_sym].first
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_line_without_highlighting
|
25
|
+
assert_equal " t(:'baar')\n", occurence(:baar).line
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_line_with_highlighting
|
29
|
+
assert_equal " t(\e[0;31;1m:'baar'\e[0m)\n", occurence(:baar).line(true)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_occurence_line_num
|
33
|
+
assert_equal 3, occurence.line_num
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_occurence_column
|
37
|
+
assert_equal 7, occurence.column
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_occurence_length
|
41
|
+
assert_equal 4, occurence.length
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_original_key
|
45
|
+
assert ":bar", occurence.original_key
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_content_head
|
49
|
+
assert_equal "def foo\n t(", occurence.content_head[-14, 999]
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_content_tail
|
53
|
+
assert_equal ")\n t(:\"baaar\")\n", occurence.content_tail[0, 18]
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_line_head
|
57
|
+
assert_equal " t(", occurence.line_head
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_line_tail
|
61
|
+
assert_equal ")\n", occurence.line_tail
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_context_returns_the_context_of_the_occurence_with_2_lines_setting
|
65
|
+
context = occurence(:baar).context.split("\n")
|
66
|
+
assert_equal 5, context.length
|
67
|
+
assert_equal " t(\e[0;31;1m:'baar'\e[0m)", context[2]
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_context_returns_the_context_of_the_occurence_with_3_lines_setting
|
71
|
+
I18n::Keys::Occurence.context_lines = 3
|
72
|
+
context = occurence(:baar).context.split("\n")
|
73
|
+
assert_equal 7, context.length
|
74
|
+
assert_equal " t(\e[0;31;1m:'baar'\e[0m)", context[3]
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_replace_simple_symbol_with_simple_symbol
|
78
|
+
bar = occurence(:bar)
|
79
|
+
bar.replace!(:oooooooo)
|
80
|
+
assert_equal " t(\e[0;31;1m:oooooooo\e[0m)\n", bar.line(true)
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_replace_simple_symbol_with_quoted_symbol
|
84
|
+
bar = occurence(:bar)
|
85
|
+
bar.replace!(:'oooo.oooo')
|
86
|
+
assert_equal " t(\e[0;31;1m:\"oooo.oooo\"\e[0m)\n", bar.line(true)
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_replace_simple_symbol_with_string
|
90
|
+
bar = occurence(:bar)
|
91
|
+
bar.replace!('oooooooo')
|
92
|
+
assert_equal " t(\e[0;31;1m:oooooooo\e[0m)\n", bar.line(true)
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_replace_quoted_symbol_with_simple_symbol
|
96
|
+
bar = occurence(:'foo.bar')
|
97
|
+
bar.replace!(:oooooooo)
|
98
|
+
assert_equal " t(\e[0;31;1m:oooooooo\e[0m)\n", bar.line(true)
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_replace_quoted_symbol_with_quoted_symbol
|
102
|
+
bar = occurence(:'foo.bar')
|
103
|
+
bar.replace!(:'oooo.oooo')
|
104
|
+
assert_equal " t(\e[0;31;1m:\"oooo.oooo\"\e[0m)\n", bar.line(true)
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_replace_quoted_symbol_with_string
|
108
|
+
bar = occurence(:'foo.bar')
|
109
|
+
bar.replace!('oooooooo')
|
110
|
+
assert_equal " t(\e[0;31;1m:oooooooo\e[0m)\n", bar.line(true)
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_replace_string_with_simple_symbol
|
114
|
+
bar = occurence('bar_1')
|
115
|
+
bar.replace!(:oooooooo)
|
116
|
+
assert_equal " t(\e[0;31;1m:oooooooo\e[0m)\n", bar.line(true)
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_replace_string_with_quoted_symbol
|
120
|
+
bar = occurence('bar_1')
|
121
|
+
bar.replace!(:'oooo.oooo')
|
122
|
+
assert_equal " t(\e[0;31;1m:\"oooo.oooo\"\e[0m)\n", bar.line(true)
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_replace_string_with_string
|
126
|
+
bar = occurence('bar_1')
|
127
|
+
bar.replace!('oooooooo')
|
128
|
+
assert_equal " t(\e[0;31;1m:oooooooo\e[0m)\n", bar.line(true)
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class RubyParserTest < Test::Unit::TestCase
|
4
|
+
def test_sexp_filename
|
5
|
+
filename = File.dirname(__FILE__) + '/fixtures/source_1.rb'
|
6
|
+
sexp = I18n::RubyParser.new.parse(File.read(filename), filename)
|
7
|
+
assert_equal filename, sexp.file
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_sexp_source_positions
|
11
|
+
assert_equal 2, 't(:foo)'.to_sexp.find_node(:lit).source_start_pos
|
12
|
+
assert_equal 5, 't(:foo)'.to_sexp.find_node(:lit).source_end_pos
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_sexp_source_symbol
|
16
|
+
assert_equal ':foo', 't(:foo)'.to_sexp.find_node(:lit).source
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_sexp_source_symbol_and_options
|
20
|
+
assert_equal ':foo', 't(:foo, :bar => :baz)'.to_sexp.find_node(:lit).source
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_sexp_source_symbol_with_double_quotes
|
24
|
+
assert_equal ':"foo"', 't(:"foo")'.to_sexp.find_node(:lit).source
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_sexp_source_symbol_with_double_quotes_and_options
|
28
|
+
assert_equal ':"foo"', 't(:"foo", :bar => :baz)'.to_sexp.find_node(:lit).source
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_sexp_source_symbol_with_single_quotes
|
32
|
+
assert_equal ":'foo'", "t(:'foo')".to_sexp.find_node(:lit).source
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_sexp_source_symbol_with_single_quotes_and_options
|
36
|
+
assert_equal ":'foo'", "t(:'foo', :bar => :baz)".to_sexp.find_node(:lit).source
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_sexp_source_string_with_double_quotes
|
40
|
+
assert_equal '"foo"', 't("foo")'.to_sexp.find_node(:str).source
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_sexp_source_string_with_double_quotes_and_options
|
44
|
+
assert_equal '"foo"', 't("foo", :bar => :baz)'.to_sexp.find_node(:str).source
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_sexp_source_string_with_single_quotes
|
48
|
+
assert_equal "'foo'", "t('foo')".to_sexp.find_node(:str).source
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_sexp_source_string_with_single_quotes_and_options
|
52
|
+
assert_equal "'foo'", "t('foo', :bar => :baz)".to_sexp.find_node(:str).source
|
53
|
+
end
|
54
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: i18n-tools
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sven Fuchs
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-05-26 09:00:00 +02:00
|
13
|
+
default_executable: i18n-keys
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: visionmedia-commander
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - "="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.5.7
|
24
|
+
version:
|
25
|
+
description: Tools for Ruby/Rails I18n
|
26
|
+
email: rails-i18n@googlegroups.com
|
27
|
+
executables:
|
28
|
+
- i18n-keys
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files: []
|
32
|
+
|
33
|
+
files:
|
34
|
+
- bin/i18n-keys
|
35
|
+
- lib/ansi.rb
|
36
|
+
- lib/i18n/keys/commands.rb
|
37
|
+
- lib/i18n/keys/formatter.rb
|
38
|
+
- lib/i18n/keys/index.rb
|
39
|
+
- lib/i18n/keys/occurence.rb
|
40
|
+
- lib/i18n/keys.rb
|
41
|
+
- lib/i18n/parser/erb_parser.rb
|
42
|
+
- lib/i18n/parser/ruby_parser.rb
|
43
|
+
- MIT-LICENSE
|
44
|
+
- README.textile
|
45
|
+
has_rdoc: false
|
46
|
+
homepage: http://rails-i18n.org
|
47
|
+
licenses: []
|
48
|
+
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options: []
|
51
|
+
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: "0"
|
59
|
+
version:
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: "0"
|
65
|
+
version:
|
66
|
+
requirements: []
|
67
|
+
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 1.3.5
|
70
|
+
signing_key:
|
71
|
+
specification_version: 2
|
72
|
+
summary: Tools for Ruby/Rails I18n
|
73
|
+
test_files:
|
74
|
+
- test/all.rb
|
75
|
+
- test/commands_test.rb
|
76
|
+
- test/erb_parser_test.rb
|
77
|
+
- test/fixtures/source_1.rb
|
78
|
+
- test/fixtures/source_2.rb
|
79
|
+
- test/fixtures/template.html.erb
|
80
|
+
- test/index_test.rb
|
81
|
+
- test/keys_test.rb
|
82
|
+
- test/occurence_test.rb
|
83
|
+
- test/ruby_parser_test.rb
|
84
|
+
- test/test_helper.rb
|