revolt 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. data/README +150 -0
  2. data/Rakefile +197 -0
  3. data/bin/rv_find_levels.rb +186 -0
  4. data/bin/rv_install_level_urls.rb +191 -0
  5. data/bin/rv_install_levels.rb +76 -0
  6. data/examples/find_rv_track.rb +17 -0
  7. data/examples/install_rv_track.rb +28 -0
  8. data/lib/revolt/args.rb +46 -0
  9. data/lib/revolt/config.rb +5 -0
  10. data/lib/revolt/exceptions.rb +34 -0
  11. data/lib/revolt/fetcher/file_system.rb +31 -0
  12. data/lib/revolt/fetcher/www.rb +117 -0
  13. data/lib/revolt/fetcher.rb +30 -0
  14. data/lib/revolt/info.rb +40 -0
  15. data/lib/revolt/level.rb +298 -0
  16. data/lib/revolt/levels.rb +362 -0
  17. data/lib/revolt/logger.rb +24 -0
  18. data/lib/revolt/package/archive/analyzer/normalized.rb +50 -0
  19. data/lib/revolt/package/archive/analyzer/troubled.rb +97 -0
  20. data/lib/revolt/package/archive/analyzer.rb +34 -0
  21. data/lib/revolt/package/archive/zip/browser.rb +44 -0
  22. data/lib/revolt/package/archive.rb +35 -0
  23. data/lib/revolt/package/exe.rb +10 -0
  24. data/lib/revolt/package/installer/archive.rb +105 -0
  25. data/lib/revolt/package/installer/exe.rb +10 -0
  26. data/lib/revolt/package.rb +64 -0
  27. data/lib/revolt/util/fs_browser.rb +30 -0
  28. data/lib/revolt/util.rb +20 -0
  29. data/lib/revolt.rb +12 -0
  30. data/test/common.rb +78 -0
  31. data/test/fixtures/files/nodirs_track.zip +0 -0
  32. data/test/fixtures/files/readme.txt +1 -0
  33. data/test/fixtures/files/rickyd_track.zip +0 -0
  34. data/test/fixtures/files/standard_multi.zip +0 -0
  35. data/test/fixtures/files/standard_rev_track.zip +0 -0
  36. data/test/fixtures/files/standard_track.zip +0 -0
  37. data/test/fixtures/files/zips_inside.zip +0 -0
  38. data/test/fixtures/rv/gfx/levid.bmp +1 -0
  39. data/test/fixtures/rv/gfx/levid.bmq +1 -0
  40. data/test/fixtures/rv/gfx/levidrev.bmp +1 -0
  41. data/test/fixtures/rv/gfx/levidrev.bmq +1 -0
  42. data/test/fixtures/rv/gfx/tEsT Level.bmp +1 -0
  43. data/test/fixtures/rv/levels/levid/levid.inf +1 -0
  44. data/test/fixtures/rv/levels/levid/levid.w +1 -0
  45. data/test/fixtures/rv/levels/levid/levida.bmp +1 -0
  46. data/test/fixtures/rv/levels/levid/readme.txt +1 -0
  47. data/test/fixtures/rv/levels/levidrev/levidrev.inf +1 -0
  48. data/test/fixtures/rv/levels/levidrev/levidrev.w +1 -0
  49. data/test/fixtures/rv/levels/levidrev/levidreva.bmp +1 -0
  50. data/test/fixtures/rv/levels/levidrev/readme.txt +1 -0
  51. data/test/fixtures/rv/levels/levidrev/reversed/levidrev.cam +1 -0
  52. data/test/fixtures/rv/levels/levidrev/reversed/levidrev.fan +1 -0
  53. data/test/fixtures/rv/levels/levidrev/reversed/levidrev.fin +1 -0
  54. data/test/fixtures/rv/levels/test lEveL/TEst level.inf +4 -0
  55. data/test/fixtures/rv/levels/test lEveL/TeST level.w +1 -0
  56. data/test/fixtures/rv/levels/test lEveL/readme.txt +1 -0
  57. data/test/fixtures/rv/levels/test lEveL/reversed/TEst level.inf +1 -0
  58. data/test/fixtures/rv/levels/test lEveL/reversed/TeST level.w +1 -0
  59. data/test/fixtures/rv/levels/test lEveL/reversed/readme.txt +1 -0
  60. data/test/fixtures/rv/levels/test lEveL/reversed/test LEVELa.bmp +1 -0
  61. data/test/fixtures/rv/levels/test lEveL/test LEVELa.bmp +1 -0
  62. data/test/tc_archive_analyzer.rb +185 -0
  63. data/test/tc_args.rb +55 -0
  64. data/test/tc_args_external.rb +55 -0
  65. data/test/tc_file_system_fetcher.rb +26 -0
  66. data/test/tc_info.rb +23 -0
  67. data/test/tc_level.rb +182 -0
  68. data/test/tc_level_installer.rb +88 -0
  69. data/test/tc_level_installer_external.rb +124 -0
  70. data/test/tc_levels.rb +68 -0
  71. data/test/tc_package_track_installer.rb +174 -0
  72. data/test/ts_base.rb +14 -0
  73. data/test/ts_external.rb +7 -0
  74. metadata +133 -0
data/README ADDED
@@ -0,0 +1,150 @@
1
+ = Ruby Re-Volt Tools
2
+ A library for easy managing of Re-Volt's files in various ways.
3
+
4
+ == Requirements
5
+ gem install rubyzip
6
+
7
+ == Install
8
+ Download the gem:
9
+ http://users.tkk.fi/~ajalkane/ruby/revolt-0.5.0.gem
10
+ Install it:
11
+ gem install revolt-0.5.0.gem
12
+
13
+ == Summary
14
+ For the moment the library mostly has functionality related to
15
+ track management. This may extend in the future.
16
+
17
+ Using the library users can easily create automated
18
+ tasks. Some of the major features are:
19
+ - Install track packages from WWW server
20
+ - Move, copy and delete tracks
21
+ - Search tracks with various criteria
22
+ - Create alternative track repositories
23
+
24
+ == Documentation
25
+ Most of the important API documentation is in ReVolt::Levels and ReVolt::Level
26
+ classes. The rest of the library is usually accessed through
27
+ them.
28
+
29
+ Conventions:
30
+ - methods that return files return Pathname objects.
31
+
32
+ == Examples
33
+ Here is a listing of some very simple, but illustrative
34
+ examples of how the library could be used.
35
+
36
+ === Listing all installed track names
37
+ require 'revolt'
38
+
39
+ levels = ReVolt::Levels.installed
40
+ levels.each_level do |level|
41
+ puts "Level: " + level.name
42
+ end
43
+
44
+ === Installing a track from a web-site
45
+ require 'revolt'
46
+
47
+ levels = ReVolt::Levels.installed
48
+ levels.install('http://url.for.track/trackname.zip')
49
+
50
+ === Moving all non-favorite custom tracks to c:/removed
51
+ Note that in this example the c:/removed folder has to
52
+ exist. The favorite array has the level names of all
53
+ your favorite tracks that you want to keep, other custom
54
+ tracks are removed. If a filename given as a parameter,
55
+ reads the leves from there. Since the favorite tracks
56
+ are as strings and not as symbol, the level id is
57
+ changed to string before comparison (favorites.member?(level.id.to_s)
58
+
59
+ require 'revolt'
60
+
61
+ favorites = [
62
+ 'alderon',
63
+ 'sakura',
64
+ 're-ville'
65
+ ]
66
+
67
+ if ARGV[0]
68
+ favorites = open(ARGV[0]).readlines.map {|l| l.chomp}
69
+ end
70
+ levels = ReVolt::Levels.installed
71
+ removed = ReVolt::Levels.at('c:/removed')
72
+ removed.create_dir_structure
73
+ levels.each_custom do |level|
74
+ level.move_to(removed) if !favorites.member?(level.id.to_s)
75
+ end
76
+
77
+ === Installing everything that looks like URL
78
+ A bit more complex example. Reads input from the user and
79
+ tries installing everything that looks like an URL first
80
+ to a temporary directory. From there copies tracks to
81
+ installed tracks that do not exist already. This example
82
+ is useful as it stands for example to install track URLs
83
+ that are copy pasted to a chat.
84
+
85
+ require 'revolt'
86
+ levels = ReVolt::Levels.installed
87
+ tmplevels = ReVolt::Levels.at('./tmp')
88
+ tmplevels.create_dir_structure
89
+
90
+ # Read input from console line by line
91
+ STDIN.each_line do |possible_urls|
92
+ tmplevels.install_urls(possible_urls)
93
+ end
94
+
95
+ # Copy the levels that have arrived to tmplevels
96
+ # into installed levels
97
+ tmplevels.each do |level|
98
+ # Install only levels that do not exist already
99
+ if levels.member? level
100
+ puts "Skipping installing of " + level.to_s + " because it exists"
101
+ else
102
+ puts "Installing level " + level.to_s
103
+ level.copy_to levels
104
+ end
105
+ end
106
+
107
+ == Applications
108
+ There are a couple of applications distributed with the library
109
+ that are useful on their own
110
+
111
+ === rv_install_level_urls.rb
112
+ Reads from the console everything that looks like an URL and tries
113
+ to install it. Useful for installing easily tracks that are copy
114
+ pasted to a chat. Use the -h switch to see more usage options.
115
+
116
+ === rv_install_levels.rb
117
+ Installs track packages that are given as command line parameters.
118
+ The tracks can be on a web-server or on the file system.
119
+ For example if you have in my_tracks directory sakura.zip and
120
+ happy_track.zip that are track packages, you can install them both
121
+ with:
122
+
123
+ rv_install_levels.rb my_tracks/sakura.zip my_tracks/happy_track.zip
124
+
125
+ Or if you want to get a track from web-site use:
126
+
127
+ rv_install_levels.rb 'http://somesite.com/the_track_url'
128
+
129
+ === rv_find_levels.rb
130
+ Finds levels by various criteria from installed levels. Basically
131
+ you can find tracks by any property defined in the tracks .inf file.
132
+ The easiest way to use it is to just enter the part of the name of
133
+ the track you want to find. For examples:
134
+
135
+ rv_find_levels temple
136
+
137
+ That would search for all levels whose name contains 'temple'
138
+ (case insensitive). Another more complex example is to find
139
+ all custom tracks that can be raced in reverse mode that
140
+ have FARCLIP more than 10000:
141
+
142
+ rv_find_levels -m 'custom?,reverse?,farclip>10000'
143
+
144
+ Use the -h option to get more help. The output format is:
145
+
146
+ <level id> (<level name>) [<matched_attribute>=<matched_value>]
147
+
148
+ Trying it in practice should clear the syntax if that seems weird.
149
+
150
+
data/Rakefile ADDED
@@ -0,0 +1,197 @@
1
+ # Rakefile
2
+ require "rake/testtask"
3
+ require "rake/clean"
4
+ require "rake/rdoctask"
5
+ require "rake/gempackagetask"
6
+
7
+ # The name of your project
8
+ PROJECT = "Re-Volt tools"
9
+ MAIN_NAMESPACE = "ReVolt"
10
+ # Your name, used in packaging.
11
+ MY_NAME = "Arto Jalkanen"
12
+ # Your email address, used in packaging.
13
+ MY_EMAIL = "ajalkane@gmail.com"
14
+ # Short summary of your project, used in packaging.
15
+ PROJECT_SUMMARY = "Library for managing Re-Volt game, and some Commandline tools"
16
+ # The project's package name (as opposed to its display name). Used for
17
+ # RubyForge connectivity and packaging.
18
+ UNIX_NAME = "revolt"
19
+ # Your RubyForge user name.
20
+ RUBYFORGE_USER = ENV["RUBYFORGE_USER"] || "ajalkane"
21
+ # Directory on RubyForge where your website's files should be uploaded.
22
+ WEBSITE_DIR = "website"
23
+ # Output directory for the rdoc html files.
24
+ # If you don't have a custom homepage, and want to use the RDoc
25
+ # index.html as homepage, just set it to WEBSITE_DIR.
26
+ RDOC_HTML_DIR = "#{WEBSITE_DIR}" # /rdoc"
27
+
28
+ HAVE_EXT = nil
29
+ EXT_DIST_FILES = nil
30
+
31
+ #################
32
+ ##
33
+ ## Getting Version of library
34
+ ##
35
+ #################
36
+ REQUIRE_PATHS = ["lib"]
37
+ REQUIRE_PATHS << EXT_DIR if HAVE_EXT
38
+ $LOAD_PATH.concat(REQUIRE_PATHS)
39
+ # This library file defines the MyProject::VERSION constant.
40
+ require "#{UNIX_NAME}"
41
+ PROJECT_VERSION = eval("#{MAIN_NAMESPACE}::VERSION") # e.g., "1.0.2"
42
+
43
+ # Options common to RDocTask AND Gem::Specification.
44
+ # The --main argument specifies which file appears on the index.html page
45
+ GENERAL_RDOC_OPTS = {
46
+ "--title" => "#{PROJECT} API documentation",
47
+ "--main" => "README"
48
+ }
49
+
50
+ # Additional RDoc formatted files, besides the Ruby source files.
51
+ RDOC_FILES = FileList["README"]
52
+ # Remove the following line if you don't want to extract RDoc from
53
+ # the extension C sources.
54
+ # RDOC_FILES.include(EXT_SOURCES)
55
+ # Ruby library code.
56
+ LIB_FILES = FileList["lib/**/*.rb"]
57
+ # Filelist with Test::Unit test cases.
58
+ TEST_FILES = FileList["test/ts_base.rb"]
59
+ # Executable scripts, all non-garbage files under bin/.
60
+ BIN_FILES = FileList["bin/*"]
61
+ # This filelist is used to create source packages.
62
+ # Include all Ruby and RDoc files.
63
+ DIST_FILES = FileList["**/*.rb", "**/*.rdoc"]
64
+ DIST_FILES.include("Rakefile")
65
+ DIST_FILES.include(BIN_FILES)
66
+ DIST_FILES.include("test/fixtures/**/*")
67
+ DIST_FILES.include("#{WEBSITE_DIR}/**/*.{html,css}", "man/*.[0-9]")
68
+ # Don't package files which are autogenerated by RDocTask
69
+ DIST_FILES.exclude(/^(\.\/)?#{RDOC_HTML_DIR}(\/|$)/)
70
+ # Include extension source files.
71
+ DIST_FILES.include(EXT_DIST_FILES) if EXT_DIST_FILES
72
+ # Don't package temporary files, perhaps created by tests.
73
+ DIST_FILES.exclude("**/temp_*", "**/*.tmp")
74
+ # Don't get into recursion...
75
+ DIST_FILES.exclude(/^(\.\/)?pkg(\/|$)/)
76
+
77
+ # Run the tests if rake is invoked without arguments.
78
+ task "default" => ["test"]
79
+
80
+ test_task_name = HAVE_EXT ? "run-tests" : "test"
81
+ Rake::TestTask.new(test_task_name) do |t|
82
+ # t.libs << "test"
83
+ t.test_files = TEST_FILES
84
+ t.libs = REQUIRE_PATHS
85
+ end
86
+
87
+ # The "rdoc" task generates API documentation.
88
+
89
+ Rake::RDocTask.new("rdoc") do |t|
90
+ t.rdoc_files = RDOC_FILES + LIB_FILES
91
+ t.title = GENERAL_RDOC_OPTS["--title"]
92
+ t.main = GENERAL_RDOC_OPTS["--main"]
93
+ t.rdoc_dir = RDOC_HTML_DIR
94
+ end
95
+
96
+ GEM_SPEC = Gem::Specification.new do |s|
97
+ s.name = UNIX_NAME
98
+ s.version = PROJECT_VERSION
99
+ s.summary = PROJECT_SUMMARY
100
+ s.rubyforge_project = UNIX_NAME
101
+ s.homepage = "http://#{UNIX_NAME}.rubyforge.org/"
102
+ s.author = MY_NAME
103
+ s.email = MY_EMAIL
104
+ s.files = DIST_FILES
105
+ s.test_files = TEST_FILES
106
+ s.executables = BIN_FILES.map { |fn| File.basename(fn) }
107
+ s.has_rdoc = true
108
+ s.extra_rdoc_files = RDOC_FILES
109
+ s.rdoc_options = GENERAL_RDOC_OPTS.to_a.flatten
110
+ if HAVE_EXT
111
+ s.extensions = EXTCONF_FILES
112
+ s.require_paths << EXT_DIR
113
+ end
114
+ end
115
+
116
+ # Now we can generate the package-related tasks.
117
+ Rake::GemPackageTask.new(GEM_SPEC) do |pkg|
118
+ pkg.need_zip = true
119
+ pkg.need_tar = true
120
+ end
121
+
122
+ desc "Upload website to RubyForge. " +
123
+ "scp will prompt for your RubyForge password."
124
+ task "publish-website" => ["rdoc"] do
125
+ rubyforge_path = "/var/www/gforge-projects/#{UNIX_NAME}/"
126
+ sh "scp -r #{WEBSITE_DIR}/* " +
127
+ "#{RUBYFORGE_USER}@rubyforge.org:#{rubyforge_path}",
128
+ :verbose => true
129
+ end
130
+
131
+ task "rubyforge-setup" do
132
+ unless File.exist?(File.join(ENV["HOME"], ".rubyforge"))
133
+ puts "rubyforge will ask you to edit its config.yml now."
134
+ puts "Please set the `username' and `password' entries"
135
+ puts "to your RubyForge username and RubyForge password!"
136
+ puts "Press ENTER to continue."
137
+ $stdin.gets
138
+ sh "rubyforge setup", :verbose => true
139
+ end
140
+ end
141
+
142
+ task "rubyforge-login" => ["rubyforge-setup"] do
143
+ # Note: We assume that username and password were set in
144
+ # rubyforge's config.yml.
145
+ sh "rubyforge login", :verbose => true
146
+ end
147
+
148
+ task "publish-packages" => ["package", "rubyforge-login"] do
149
+ # Upload packages under pkg/ to RubyForge
150
+ # This task makes some assumptions:
151
+ # * You have already created a package on the "Files" tab on the
152
+ # RubyForge project page. See pkg_name variable below.
153
+ # * You made entries under package_ids and group_ids for this
154
+ # project in rubyforge's config.yml. If not, eventually read
155
+ # "rubyforge --help" and then run "rubyforge setup".
156
+ pkg_name = ENV["PKG_NAME"] || UNIX_NAME
157
+ cmd = "rubyforge add_release #{UNIX_NAME} #{pkg_name} " +
158
+ "#{PROJECT_VERSION} #{UNIX_NAME}-#{PROJECT_VERSION}"
159
+ cd "pkg" do
160
+ sh(cmd + ".gem", :verbose => true)
161
+ sh(cmd + ".tgz", :verbose => true)
162
+ sh(cmd + ".zip", :verbose => true)
163
+ end
164
+ end
165
+
166
+ # The "prepare-release" task makes sure your tests run, and then generates
167
+ # files for a new release.
168
+ desc "Run tests, generate RDoc and create packages."
169
+ task "prepare-release" => ["clobber"] do
170
+ puts "Preparing release of #{PROJECT} version #{VERSION}"
171
+ Rake::Task["test"].invoke
172
+ Rake::Task["rdoc"].invoke
173
+ Rake::Task["package"].invoke
174
+ end
175
+
176
+ # The "publish" task is the overarching task for the whole project. It
177
+ # builds a release and then publishes it to RubyForge.
178
+ desc "Publish new release of #{PROJECT}"
179
+ task "publish" => ["prepare-release"] do
180
+ puts "Uploading documentation..."
181
+ Rake::Task["publish-website"].invoke
182
+ puts "Checking for rubyforge command..."
183
+ `rubyforge --help`
184
+ if $? == 0
185
+ puts "Uploading packages..."
186
+ Rake::Task["publish-packages"].invoke
187
+ puts "Release done!"
188
+ else
189
+ puts "Can't invoke rubyforge command."
190
+ puts "Either install rubyforge with 'gem install rubyforge'"
191
+ puts "and retry or upload the package files manually!"
192
+ end
193
+ end
194
+
195
+
196
+ # To get an overview of this extensive Rakefile, run rake -T:
197
+
@@ -0,0 +1,186 @@
1
+ #!/usr/bin/ruby
2
+ #
3
+ require 'optparse'
4
+ require 'pp'
5
+ require 'revolt'
6
+ require 'set'
7
+
8
+ def main
9
+ cmd = CmdArguments.new(ARGV)
10
+ ReVolt::Logger.enable if cmd[:debug]
11
+ levels = ReVolt::Levels.at(cmd[:base])
12
+ levels.each_level do |level|
13
+ matches = {}
14
+ nmatches = 0
15
+ cmd[:match].each do |op|
16
+ value = level_cmp_match(op, level)
17
+ if value != nil
18
+ # level.inf[key].send(:=~, ''/#{value}/i')) # =~ /#{value}/i
19
+ matches[op[:name]] = value # level.inf[key]
20
+ nmatches += 1
21
+ end
22
+ end
23
+ if cmd[:match].size == nmatches
24
+ keyvaluestr = matches.map{|(k,v)|"#{k}=#{v}"}.join(', ')
25
+ puts "%s [%s]" % [level.to_s, keyvaluestr]
26
+ end
27
+ end
28
+ end
29
+
30
+ def level_cmp_match(op, level)
31
+ return false if !level || !op
32
+ args1 = [op[:method]]
33
+ args2 = [op[:cmp], op[:expect]]
34
+ obj = level
35
+ ret_value = true
36
+ if op[:method] == :inf
37
+ lvlinfval = level.inf[op[:infkey]]
38
+ return false if !lvlinfval
39
+ obj = lvlinfval
40
+ # op[:method] = [op[:infcmp], op[:infval]]
41
+ ret_value = lvlinfval
42
+
43
+ # Check if comparing to a number (if non digits, not a number)
44
+ #ReVolt::Logger.debug("Second class: #{s.class} value: #{s}")
45
+ case
46
+ when op[:infcmp] == :=~:
47
+ ReVolt::Logger.debug("Its a regexp")
48
+ # If a regular expression, do the comparison to reg exp match's return value
49
+ obj = lvlinfval =~ /#{op[:infval]}/i
50
+ # If the return value is integer, a match was found
51
+ args1 = [:is_a?, Integer]
52
+ when !(op[:infval] =~ /[^\d]/)
53
+ ReVolt::Logger.debug("Its a number")
54
+ # If comparing to an integer
55
+ # Return false unless both comparisons to integer
56
+ return false if lvlinfval =~ /[^\d]/
57
+ # Do the comparison as integers
58
+ obj = lvlinfval.to_i
59
+ args1 = [op[:infcmp], op[:infval].to_i]
60
+ else
61
+ # obj = lvlinfval
62
+ args1 = [op[:infcmp], op[:infval]]
63
+ end
64
+ end
65
+
66
+ ReVolt::Logger.debug("Sending operation #{args1} to object #{obj.class} with value #{obj}")
67
+ ReVolt::Logger.debug("Args2: #{args2}") # Sending operation #{args} to object #{obj.class}")
68
+ # ret = obj.send(infcmp, infval) # *args)
69
+ # ret = (obj =~ infval)
70
+ # ReVolt::Logger.debug("Return value: #{ret}, class: #{ret.class}")
71
+ if (obj.send(*args1)).send(*args2)
72
+ ReVolt::Logger.debug("Returning value #{ret_value}")
73
+ return ret_value
74
+ end
75
+ nil
76
+ end
77
+
78
+ class CmdArguments < Hash
79
+ def initialize(cmd)
80
+ super()
81
+
82
+ inf_matches = []
83
+ self[:base] = ReVolt::Info::path
84
+
85
+ opts = OptionParser.new do |opts|
86
+ opts.banner = "Usage: #$0 [options] [name_match]\n"
87
+
88
+ opts.separator "Examples:"
89
+ opts.separator " Searches for all tracks which name contains temple:"
90
+ opts.separator " #$0 temple"
91
+ opts.separator " All tracks which farclip is more than 31000 and startgrid is 3"
92
+ opts.separator " #$0 -m 'farclip>31000,startgrid=3'"
93
+ opts.separator " All custom tracks that can be raced in reversed mode"
94
+ opts.separator " #$0 -m 'reverse?,custom?'"
95
+
96
+ opts.separator ""
97
+ opts.separator "Operators:"
98
+ opts.separator " <op> in the options can be replaced with:"
99
+ opts.separator " = equality"
100
+ opts.separator " < smaller than"
101
+ opts.separator " > larger than"
102
+ opts.separator " =~ regular expression match"
103
+ opts.separator ""
104
+ opts.separator " The match can include also the following toggles:"
105
+ opts.separator " reversed?"
106
+ opts.separator " stock?"
107
+ opts.separator " custom?"
108
+
109
+ opts.separator ""
110
+
111
+ opts.separator "Options:"
112
+
113
+ opts.on('-m', '--match [key<op>match[,key2<op>match2[,...]]]', Array,
114
+ 'Matches values in the .inf file with operator') do |value|
115
+ # 'Match to values in level inf files') do |value|
116
+ inf_matches = value
117
+ end
118
+ opts.on('-d', '--debug',
119
+ 'Outputs debug information') do
120
+ self[:debug] = true
121
+ end
122
+ opts.on('-b', '--base [DIR]',
123
+ 'RV base path. Defaults to RV installation') do |value|
124
+ self[:base] = value
125
+ end
126
+
127
+ opts.on_tail('-h', '--help',
128
+ 'Display this help and exit') do
129
+ puts opts
130
+ exit(1)
131
+ end
132
+ end
133
+
134
+ opts.parse!(cmd)
135
+
136
+ if cmd.size != 0
137
+ inf_matches << '%s=~%s' % ['name', cmd[0]]
138
+ end
139
+
140
+ # If input file not specified, at least start date is required
141
+ if inf_matches.size == 0
142
+ puts "Error: no matches specified"
143
+ STDERR.puts opts
144
+ exit 1
145
+ end
146
+
147
+ self[:match] = []
148
+ inf_matches.each do |keyvalue|
149
+ op = {
150
+ :cmp => :==,
151
+ :expect => true
152
+ }
153
+ case keyvalue
154
+ when 'reverse?','stock?','custom?'
155
+ op.merge!({
156
+ :method => keyvalue.to_sym,
157
+ :name => keyvalue
158
+ })
159
+ else
160
+ ((key,cmp,value)) = keyvalue.scan(/(\w+)(=~|<|>|=)(.+)/)
161
+ # (key, value) = keyvalue.split('=')
162
+ if key.nil?
163
+ STDERR.puts "Error: invalid match '#{keyvalue}', should be key<cmp>value"
164
+ STDERR.puts " where cmp is comparison type, one of: =,<,> or =~"
165
+ STDERR.puts " Example: name=~temple"
166
+ STDERR.puts opts
167
+ exit 1
168
+ end
169
+
170
+ cmp = '==' if cmp == '='
171
+ op.merge!({
172
+ :method => :inf,
173
+ :infkey => key.downcase.to_sym,
174
+ :infcmp => cmp.to_sym,
175
+ :infval => value,
176
+ :name => key,
177
+ })
178
+
179
+ end
180
+ self[:match] << op
181
+ end
182
+ end
183
+ end
184
+
185
+
186
+ main