rfs 0.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README +110 -0
- data/Rakefile.rb +7 -5
- data/bin/RenameFileSet.rbw +7 -9
- data/bin/rfs.rb +86 -49
- data/description.txt +1 -0
- data/lib/errors.rb +6 -0
- data/lib/gui.rb +21 -6
- data/lib/innate/array.rb +81 -72
- data/lib/innate/filelines.rb +1 -1
- data/lib/innate/regexp.rb +6 -2
- data/lib/innate/roman.rb +6 -5
- data/lib/innate/test/testarray.rb +71 -35
- data/lib/innate/test/testroman.rb +4 -0
- data/lib/options.rb +22 -23
- data/lib/providers.rb +60 -1
- data/lib/rename_functions.rb +18 -4
- data/lib/renamer.rb +9 -3
- data/lib/results.rb +17 -7
- data/profile.txt +226 -0
- data/tests/test_rename_functions.rb +10 -2
- metadata +8 -6
- data/lib/RenameFileSet.bak.rb +0 -372
- data/tests/test_helper.rb +0 -147
data/README
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
:main:README
|
2
|
+
|
3
|
+
= Rename File Set
|
4
|
+
|
5
|
+
Rename File Set is a utility for transforming the name of matching files using the full power of regular expressions. I originally created this program to help organize my mp3 collection, but it has proven to be generally useful.
|
6
|
+
|
7
|
+
As I have added features, the program has been extesively refactored. It is DRY and very modular. It is also very well tested. Features can now be added or changed very easily.
|
8
|
+
|
9
|
+
Author:: Darrick Wiebe
|
10
|
+
Copyright:: Copyright (c) 2005 Darrick Wiebe
|
11
|
+
License:: Distributed under the MIT Licence (see MIT-LICENCE file)
|
12
|
+
|
13
|
+
== Command Line Interface
|
14
|
+
|
15
|
+
There are two entry points to the command line version of the program. The primary one is +rfs.rb+. +rfsd.rb+ just adds debugging options.
|
16
|
+
|
17
|
+
=== Usage
|
18
|
+
|
19
|
+
rfs.rb [options] [path] [path] ...
|
20
|
+
|
21
|
+
If no path is specified, the current directory is used.
|
22
|
+
|
23
|
+
==== The Four Primary Modes of Operation
|
24
|
+
|
25
|
+
[<tt>--list</tt>]
|
26
|
+
List Mode: List all files in the folder
|
27
|
+
[<tt>--match</tt>]
|
28
|
+
Match Mode: List all matching files but don't make any changes
|
29
|
+
[<tt>--test</tt>]
|
30
|
+
Testing Mode: Display the results without making any changes
|
31
|
+
[<tt>--commit</tt>]
|
32
|
+
Commit Mode: Actually perform the operation on the target files and
|
33
|
+
display the results. By default, <tt>--confirm</tt> is turned on, see below.
|
34
|
+
|
35
|
+
==== Search
|
36
|
+
|
37
|
+
[<tt>--search</tt> <i>regular expression</i>]
|
38
|
+
This option is required for
|
39
|
+
|
40
|
+
==== Behaviour Modification Options
|
41
|
+
|
42
|
+
[<tt>--confirm</tt>]
|
43
|
+
Ask for confirmation before committing a change with a prompt like:
|
44
|
+
|
45
|
+
<tt>"./original" => "new_name"? [Yes/No/All/Cancel] (yes) _</tt>
|
46
|
+
|
47
|
+
or
|
48
|
+
|
49
|
+
<tt>"./original" => existing file "new_name"? [Yes/No/All/Cancel] (yes) _</tt>
|
50
|
+
|
51
|
+
This option is on by default.
|
52
|
+
[<tt>--noconfirm</tt>]
|
53
|
+
Don't confirm changes.
|
54
|
+
[<tt>--capture</tt> <i>capture number</i>]
|
55
|
+
Specifies which capture in the regular expression should
|
56
|
+
be used or replaced. By default the <b>first</b> capture
|
57
|
+
is used. This option affects all regular expressions used.
|
58
|
+
If the expression has no captures, the whole match is
|
59
|
+
used, and this setting has no effect.
|
60
|
+
[<tt>--filter</tt> <i>regular expression</i>]
|
61
|
+
Filters out all <b>matching</b> files or directories.
|
62
|
+
Multiple filters may be specified.
|
63
|
+
[<tt>--keep</tt> <i>regular expression</i>]
|
64
|
+
Filters out all <b>non-matching</b> files or directories.
|
65
|
+
Multiple filters may be specified.
|
66
|
+
[<tt>--force</tt>]
|
67
|
+
Overwrite existing files. If <tt>--confirm</tt> is on, the
|
68
|
+
confirmation message will
|
69
|
+
[<tt>--ignorecase</tt>]
|
70
|
+
Make all regular expressions case-insensitive.
|
71
|
+
[<tt>--recursive</tt>]
|
72
|
+
Recursively descend into the paths specified.
|
73
|
+
[<tt>--reverse</tt>]
|
74
|
+
Iterates through files in reverse order.
|
75
|
+
|
76
|
+
==== Primary Functions
|
77
|
+
|
78
|
+
[<tt>--add</tt> <i>number</i>]
|
79
|
+
Add <tt>number</tt> to <tt>the capture</tt>.
|
80
|
+
[<tt>--count</tt> <i>start</i>]
|
81
|
+
Replace <tt>the capture</tt> with the count. <tt>succ</tt> is
|
82
|
+
used to increment, so you can use either letters or numbers.
|
83
|
+
[<tt>--</tt> <i></i>]
|
84
|
+
|
85
|
+
[<tt>--</tt> <i></i>]
|
86
|
+
|
87
|
+
[<tt>--</tt> <i></i>]
|
88
|
+
|
89
|
+
[<tt>--</tt> <i></i>]
|
90
|
+
|
91
|
+
[<tt>--</tt> <i></i>]
|
92
|
+
|
93
|
+
[<tt>--</tt> <i></i>]
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
==== Display Options
|
98
|
+
|
99
|
+
[<tt>--</tt>]
|
100
|
+
|
101
|
+
[<tt>--</tt>]
|
102
|
+
|
103
|
+
[<tt>--</tt>]
|
104
|
+
|
105
|
+
[<tt>--</tt>]
|
106
|
+
|
107
|
+
|
108
|
+
|
109
|
+
The program
|
110
|
+
|
data/Rakefile.rb
CHANGED
@@ -4,7 +4,7 @@ require 'rake/gempackagetask'
|
|
4
4
|
require 'rake/contrib/rubyforgepublisher'
|
5
5
|
|
6
6
|
PKG_NAME = 'rfs'
|
7
|
-
PKG_VERSION = '0.
|
7
|
+
PKG_VERSION = '0.2'
|
8
8
|
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
9
9
|
|
10
10
|
RELEASE_NAME = "REL #{PKG_VERSION}"
|
@@ -34,7 +34,10 @@ dist_dirs = [ "lib", "tests"]
|
|
34
34
|
spec = Gem::Specification.new do |s|
|
35
35
|
s.name = PKG_NAME
|
36
36
|
s.version = PKG_VERSION
|
37
|
-
s.summary =
|
37
|
+
s.summary = <<-EOD
|
38
|
+
A utility that allows you to use regular expressions to rename
|
39
|
+
large sets of files or folders. Fxruby and cmd-line interfaces.
|
40
|
+
EOD
|
38
41
|
s.description = <<-EOD
|
39
42
|
Rename File Set is a powerful way to manage large or small
|
40
43
|
sets of files such as mp3 collections etc. It uses the full
|
@@ -47,7 +50,7 @@ spec = Gem::Specification.new do |s|
|
|
47
50
|
).delete_if { |item| item.include?( "\.svn" ) || item.include?("\pkg") }
|
48
51
|
s.require_path = 'lib'
|
49
52
|
s.has_rdoc = false
|
50
|
-
|
53
|
+
s.test_files = ['./tests/test_rename_functions.rb', './lib/innate/test/all_tests.rb']
|
51
54
|
|
52
55
|
s.bindir = 'bin'
|
53
56
|
s.executables << 'rfs.rb'
|
@@ -63,13 +66,12 @@ end
|
|
63
66
|
Rake::GemPackageTask.new(spec) do |p|
|
64
67
|
p.gem_spec = spec
|
65
68
|
p.need_tar = true
|
66
|
-
|
69
|
+
p.need_zip = true
|
67
70
|
end
|
68
71
|
|
69
72
|
desc "Publish the beta gem"
|
70
73
|
task :pgem => [:package] do
|
71
74
|
Rake::SshFilePublisher.new("pangloss@rfs.rubyforge.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
|
72
|
-
#`ssh davidhh@wrath.rubyonrails.com './gemupdate.sh'`
|
73
75
|
end
|
74
76
|
|
75
77
|
desc "Publish the API documentation"
|
data/bin/RenameFileSet.rbw
CHANGED
@@ -3,12 +3,10 @@ require 'gui'
|
|
3
3
|
require 'renamer'
|
4
4
|
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
theApp.run
|
14
|
-
end
|
6
|
+
$>.sync = true
|
7
|
+
theApp = FXApp.new
|
8
|
+
theMainWindow = RenameWindow.new theApp
|
9
|
+
theMainWindow.renamer = Renamer.new
|
10
|
+
theApp.create
|
11
|
+
theMainWindow.show
|
12
|
+
theApp.run
|
data/bin/rfs.rb
CHANGED
@@ -28,7 +28,11 @@ class CommandLineInterface
|
|
28
28
|
op = OptionParser.new
|
29
29
|
file_provider = Provider::File::NonRecursive
|
30
30
|
@@options = options = {}
|
31
|
-
|
31
|
+
width = 80
|
32
|
+
# if require 'curses'
|
33
|
+
# width = Curses::stdscr.maxx
|
34
|
+
# end
|
35
|
+
@@results = CollectResults.new $>, width
|
32
36
|
renamer = Renamer.new
|
33
37
|
|
34
38
|
# basic default settings.
|
@@ -44,38 +48,49 @@ class CommandLineInterface
|
|
44
48
|
# more defaults... make configurable in the future
|
45
49
|
CommandLineInterface.confirm # confirm changes
|
46
50
|
options[:action] = :preview # dry-run mode
|
47
|
-
|
48
51
|
|
49
|
-
op.
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
52
|
+
op.banner = 'Usage: rfs.rb [options] [path] [path] ...'
|
53
|
+
op.separator "Fundamentals:"
|
54
|
+
op.on('-l', '--list', 'List original file names in folders to',
|
55
|
+
'operate on only.') {
|
56
|
+
function = :rename_replace
|
57
|
+
options[:action] = :list
|
58
|
+
@@results.list = true
|
54
59
|
}
|
55
|
-
op.
|
60
|
+
op.on('-t', '--test', 'Test run only, don\'t do anything.') {
|
56
61
|
options[:action] = :preview
|
57
62
|
}
|
58
|
-
op.
|
63
|
+
op.on('-c', '--commit', 'Commit changes: actually rename the files.') {
|
59
64
|
options[:action] = :commit
|
60
65
|
}
|
61
|
-
op.
|
62
|
-
|
63
|
-
|
64
|
-
|
66
|
+
op.on('--confirm', 'Confirm before rename.') {
|
67
|
+
CommandLineInterface.confirm
|
68
|
+
}
|
69
|
+
op.on('--noconfirm', 'Don\'t confirm.') {
|
70
|
+
CommandLineInterface.noconfirm
|
71
|
+
}
|
72
|
+
|
73
|
+
op.separator "Search:"
|
74
|
+
op.on('-s', '--search REGEXP', String, 'Search expression') {|s|
|
75
|
+
options[:search] = PrepareRegexp.new s
|
65
76
|
}
|
66
77
|
|
78
|
+
op.separator "Primary Functions:"
|
67
79
|
op.on('-a', '--add NUMBER', Integer, 'Add to capture.') {|options[:add]|
|
68
80
|
function = :rename_add
|
69
81
|
}
|
70
|
-
op.on('-C', '--count', 'Replace capture with count.') {
|
82
|
+
op.on('-C', '--count [START]', 'Replace capture with count.') {|s|
|
71
83
|
function = :rename_count
|
84
|
+
options[:count_start] = s || 1
|
72
85
|
}
|
73
86
|
op.on('--capture NUM', Integer, 'Replace the text in a specific capture.',
|
74
|
-
'Default: 1 (or whole match if
|
87
|
+
'Default: 1 (or whole match if',
|
88
|
+
'there are no captures)') {|n|
|
75
89
|
options[:capture_num] = n
|
76
90
|
}
|
77
91
|
op.on('--file [FILE]', String,
|
78
|
-
'Use files.txt or FILE as source for
|
92
|
+
'Use files.txt or FILE as source for',
|
93
|
+
'replace strings.') {|file|
|
79
94
|
options[:source] = NameFileSource.new(file || 'files.txt')
|
80
95
|
function = :rename_name_source
|
81
96
|
options[:filter] = Filter.add(options[:filter], Filter.new(/^#{file || 'files.txt'}$/))
|
@@ -83,29 +98,20 @@ class CommandLineInterface
|
|
83
98
|
options[:filter] = Filter.add(options[:filter], Filter.new(/^#{file}$/, nil, true))
|
84
99
|
end
|
85
100
|
}
|
86
|
-
op.on('-
|
87
|
-
'
|
88
|
-
|
89
|
-
|
90
|
-
op.on('-F', '--keep REGEXP', String,
|
91
|
-
'Include only matching files in the search.') {|f|
|
92
|
-
options[:filter] = Filter.add(options[:filter], FilterNonMatches.new(PrepareRegexp.new(f)))
|
93
|
-
}
|
94
|
-
op.on('--force', 'Force rename even if a file will be replaced.') {
|
95
|
-
options[:force] = true
|
96
|
-
}
|
97
|
-
op.on('-i', '--fill REGEXP', String, 'Copy -s match from previous files and fill downwards, replacing the match for this pattern.') {|f|
|
101
|
+
op.on('-i', '--fill REGEXP', String,
|
102
|
+
'Copy -s match from previous files and fill',
|
103
|
+
'downwards, replacing the match for this',
|
104
|
+
'pattern.') {|f|
|
98
105
|
options[:fill] = PrepareRegexp.new f
|
99
106
|
function = :rename_fill
|
100
107
|
}
|
101
|
-
op.on('-I', '--ignorecase', 'Make all REGEXP options case-insensitive.') {
|
102
|
-
insensitive = true
|
103
|
-
}
|
104
108
|
op.on('-n', '--roman', 'Toggle match to or from roman numerals.') {
|
105
109
|
function = :rename_roman
|
106
110
|
}
|
107
|
-
op.on('-m', '--mark [PATTERN]',
|
108
|
-
'
|
111
|
+
op.on('-m', '--mark [PATTERN]',
|
112
|
+
'Mark files if the captured pattern',
|
113
|
+
'changes. The capture in PATTERN will',
|
114
|
+
'be replaced with --mark_text.',
|
109
115
|
'Default: /()$/') {|p|
|
110
116
|
function = :rename_mark_change
|
111
117
|
options[:replace_pattern] = PrepareRegexp.new(p || '()$')
|
@@ -114,6 +120,16 @@ class CommandLineInterface
|
|
114
120
|
op.on('--mark_text TEXT', 'Default: --changed--') {|t|
|
115
121
|
options[:replace_text] = t
|
116
122
|
}
|
123
|
+
op.on('--eval EXPR', String, 'CAUTION! The expression will be',
|
124
|
+
'evaluated in the same context as',
|
125
|
+
'the rest of the program.',
|
126
|
+
'Perform eval on EXPR after',
|
127
|
+
'it has been interpolated with',
|
128
|
+
'the search captures.'
|
129
|
+
) {|expr|
|
130
|
+
options[:eval_expr] = expr
|
131
|
+
function = :rename_eval
|
132
|
+
}
|
117
133
|
op.on('-p', '--inpath REGEXP', String, 'Rename with match in full path.') {|p|
|
118
134
|
options[:pattern] = PrepareRegexp.new p
|
119
135
|
function = :rename_from_full_name
|
@@ -126,33 +142,53 @@ class CommandLineInterface
|
|
126
142
|
options[:replace] = r || ''
|
127
143
|
function = :rename_replace
|
128
144
|
}
|
129
|
-
op.on('-R', '--recursive', 'Operate on all files and folders recursively.') {
|
130
|
-
file_provider = Provider::File::Recursive
|
131
|
-
}
|
132
|
-
op.on('--reverse', 'Operate on files in reverse order.') {
|
133
|
-
reverse = true
|
134
|
-
}
|
135
145
|
op.on('--rm', 'Remove matching files.') {
|
136
146
|
function = :rename_remove
|
137
147
|
}
|
138
|
-
op.on('
|
139
|
-
|
140
|
-
}
|
141
|
-
op.on('--sort', 'Sort output') { @@results.sorted = true }
|
142
|
-
op.on('--tape', 'Convert tape numbers ie. 1A, 1B, 2A, ... to regular numbers.') {
|
148
|
+
op.on('--tape', 'Convert tape numbers.',
|
149
|
+
'ie. 3A, 3B, 4A, ... to 5, 6, 7.') {
|
143
150
|
function = :rename_tape_numbers
|
144
151
|
}
|
145
152
|
op.on('-T', '--title', 'Convert capture to title case.') {
|
146
|
-
|
153
|
+
function = :rename_capitalize
|
147
154
|
}
|
148
|
-
op.on('-u', '--up', 'Move files
|
155
|
+
op.on('-u', '--up', 'Move matching files up to parent directory.') {
|
149
156
|
function = :rename_move_up
|
150
157
|
}
|
158
|
+
|
159
|
+
op.separator "Behaviour Modifications:"
|
160
|
+
op.on('-f', '--filter REGEXP', String,
|
161
|
+
'Remove matching files from the search.') {|f|
|
162
|
+
options[:filter] = Filter.add(options[:filter], Filter.new(PrepareRegexp.new(f)))
|
163
|
+
}
|
164
|
+
op.on('-F', '--keep REGEXP', String,
|
165
|
+
'Include only matching files in the search.') {|f|
|
166
|
+
options[:filter] = Filter.add(options[:filter], FilterNonMatches.new(PrepareRegexp.new(f)))
|
167
|
+
}
|
168
|
+
op.on('--force', 'Force rename even if a file will be lost.') {
|
169
|
+
options[:force] = true
|
170
|
+
}
|
171
|
+
op.on('-I', '--ignorecase', 'Make all REGEXP options case-insensitive.') {
|
172
|
+
insensitive = true
|
173
|
+
}
|
174
|
+
op.on('-R', '--recursive',
|
175
|
+
'Recursively descend the directory',
|
176
|
+
'tree.') {
|
177
|
+
file_provider = Provider::File::Recursive
|
178
|
+
}
|
179
|
+
op.on('--reverse', 'Operate on files in reverse order.') {
|
180
|
+
reverse = true
|
181
|
+
}
|
182
|
+
|
183
|
+
|
184
|
+
op.separator "Output Options:"
|
185
|
+
op.on('--sort', 'Sort output') { @@results.sorted = true }
|
151
186
|
op.on('-q', '--quiet') { quiet = @@results.quiet = true }
|
152
187
|
op.on('-Q', '--silent') {
|
153
188
|
@@results.quiet = @@results.silent = silent = quiet = true;
|
154
189
|
options[:verbose] = print_matches = false }
|
155
|
-
op.on('-v', '--verbose', 'Vebose. Useful if you aren\'t getting
|
190
|
+
op.on('-v', '--verbose', 'Vebose. Useful if you aren\'t getting',
|
191
|
+
'the results you expect.') {
|
156
192
|
@@results.verbose = options[:verbose] = true
|
157
193
|
}
|
158
194
|
op.on('-V', '--more_verbose', 'Verbose + show breakdown of matchdata.') {
|
@@ -161,10 +197,11 @@ class CommandLineInterface
|
|
161
197
|
op.on('-x', '--sideways', 'Display in rows instead of in columns.') {
|
162
198
|
@@results.sideways = true
|
163
199
|
}
|
164
|
-
op.on('-X', '--raw_output', 'Don\'t sort and keep everything on
|
200
|
+
op.on('-X', '--raw_output', 'Don\'t sort and keep everything on separate',
|
201
|
+
'lines.') {
|
165
202
|
@@results.lineways = true
|
166
203
|
}
|
167
|
-
|
204
|
+
|
168
205
|
paths = op.parse ARGV
|
169
206
|
|
170
207
|
if paths.empty?
|
data/description.txt
CHANGED
@@ -8,6 +8,7 @@ This is a comprehensive utility for renaming sets of files. It makes full use o
|
|
8
8
|
* in path (replace with text captured from the file's full path)
|
9
9
|
* prompt (prompt for a new name for each file)
|
10
10
|
* replace (regular search and replace)
|
11
|
+
* remove (delete matching files)
|
11
12
|
* tape (replace 1A, 1B, 2A, 2B, ... with 1, 2, 3, 4, ...)
|
12
13
|
* title (Do Title Casing in the Proper English Way. It can Handle Punctuation too.)
|
13
14
|
* up (move files to parent directory)
|
data/lib/errors.rb
CHANGED
data/lib/gui.rb
CHANGED
@@ -77,6 +77,7 @@ class RenameWindow < FXMainWindow
|
|
77
77
|
}
|
78
78
|
# results on right
|
79
79
|
@results = FXText.new mainFrame, nil, 0, LAYOUT_FILL | FRAME_NORMAL | TEXT_READONLY
|
80
|
+
@results.setFont(FXFont.new(getApp(), "courier new", 7))
|
80
81
|
}
|
81
82
|
|
82
83
|
@selReplace.checkState = TRUE
|
@@ -146,9 +147,12 @@ class RenameWindow
|
|
146
147
|
end
|
147
148
|
|
148
149
|
def start(action)
|
150
|
+
# require 'innate/reload'
|
151
|
+
# reload 'providers'
|
152
|
+
|
149
153
|
s = StringIO.new
|
150
|
-
@r = CollectResults.new s
|
151
|
-
@r.lineways = true
|
154
|
+
@r = CollectResults.new s, 60
|
155
|
+
# @r.lineways = true
|
152
156
|
@r.list = action == :list
|
153
157
|
|
154
158
|
begin
|
@@ -169,8 +173,8 @@ class RenameWindow
|
|
169
173
|
def rename(name, args = {})
|
170
174
|
args[:search] ||= PrepareRegexp.new @search.text
|
171
175
|
args[:filter] = Filter.add(args[:filter], Filter.new(/^\.+$/))
|
172
|
-
args[:file_provider] =
|
173
|
-
|
176
|
+
args[:file_provider] =
|
177
|
+
Provider::File::NonRecursive.new(Provider::Folder::Tree.new(@dirList))
|
174
178
|
PrepareRegexp.each(args) do |k, v|
|
175
179
|
args[k] = t = v.create(false, false, true) do |mode, output|
|
176
180
|
@r.output(mode, output)
|
@@ -182,7 +186,12 @@ class RenameWindow
|
|
182
186
|
end
|
183
187
|
end
|
184
188
|
|
185
|
-
|
189
|
+
#--
|
190
|
+
# special functions
|
191
|
+
#
|
192
|
+
# these should be changed to just return a hash of special
|
193
|
+
# options for the function. The rest is all wet.
|
194
|
+
#++
|
186
195
|
|
187
196
|
def rename_replace action
|
188
197
|
rename :rename_replace, :replace => @replace.text, :action => action
|
@@ -202,15 +211,21 @@ class RenameWindow
|
|
202
211
|
|
203
212
|
def rename_mark_change action
|
204
213
|
rename(:rename_mark_change,
|
205
|
-
:replace_pattern => PrepareRegexp.new('()$/'),
|
214
|
+
:replace_pattern => PrepareRegexp.new('()$/'), # could add boxes for these options
|
206
215
|
:replace_text => '--changed--',
|
207
216
|
:action => action)
|
208
217
|
end
|
209
218
|
|
210
219
|
def rename_files_txt action
|
220
|
+
# note the name change
|
211
221
|
rename(:rename_name_source,
|
212
222
|
:source => NameFileSource.new('files.txt'),
|
213
223
|
:filter => Filter.new(/^files.txt$/),
|
214
224
|
:action => action)
|
215
225
|
end
|
226
|
+
|
227
|
+
def rename_count action
|
228
|
+
rename(:rename_count, :count_start => 1, # could add a box for this option.
|
229
|
+
:action => action)
|
230
|
+
end
|
216
231
|
end
|