esod-client 0.1.0

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 (83) hide show
  1. data/EXAMPLES +140 -0
  2. data/GEM_RELEASE +19 -0
  3. data/README +10 -0
  4. data/Rakefile +14 -0
  5. data/VERSION +1 -0
  6. data/esod-client.gemspec +118 -0
  7. data/esod-client.rb +35 -0
  8. data/lib/activesupport-2.2.2/CHANGELOG +1257 -0
  9. data/lib/activesupport-2.2.2/README +43 -0
  10. data/lib/activesupport-2.2.2/README.CFT +2 -0
  11. data/lib/activesupport-2.2.2/lib/active_support.rb +26 -0
  12. data/lib/activesupport-2.2.2/lib/active_support/base64.rb +33 -0
  13. data/lib/activesupport-2.2.2/lib/active_support/basic_object.rb +24 -0
  14. data/lib/activesupport-2.2.2/lib/active_support/buffered_logger.rb +122 -0
  15. data/lib/activesupport-2.2.2/lib/active_support/cache.rb +223 -0
  16. data/lib/activesupport-2.2.2/lib/active_support/cache/compressed_mem_cache_store.rb +20 -0
  17. data/lib/activesupport-2.2.2/lib/active_support/cache/drb_store.rb +15 -0
  18. data/lib/activesupport-2.2.2/lib/active_support/cache/file_store.rb +72 -0
  19. data/lib/activesupport-2.2.2/lib/active_support/cache/mem_cache_store.rb +127 -0
  20. data/lib/activesupport-2.2.2/lib/active_support/cache/memory_store.rb +52 -0
  21. data/lib/activesupport-2.2.2/lib/active_support/cache/synchronized_memory_store.rb +47 -0
  22. data/lib/activesupport-2.2.2/lib/active_support/callbacks.rb +280 -0
  23. data/lib/activesupport-2.2.2/lib/active_support/core_ext.rb +6 -0
  24. data/lib/activesupport-2.2.2/lib/active_support/core_ext/hash.rb +14 -0
  25. data/lib/activesupport-2.2.2/lib/active_support/core_ext/hash/conversions.rb +259 -0
  26. data/lib/activesupport-2.2.2/lib/active_support/core_ext/hash/deep_merge.rb +23 -0
  27. data/lib/activesupport-2.2.2/lib/active_support/core_ext/hash/diff.rb +19 -0
  28. data/lib/activesupport-2.2.2/lib/active_support/core_ext/hash/except.rb +25 -0
  29. data/lib/activesupport-2.2.2/lib/active_support/core_ext/hash/indifferent_access.rb +137 -0
  30. data/lib/activesupport-2.2.2/lib/active_support/core_ext/hash/keys.rb +52 -0
  31. data/lib/activesupport-2.2.2/lib/active_support/core_ext/hash/reverse_merge.rb +35 -0
  32. data/lib/activesupport-2.2.2/lib/active_support/core_ext/hash/slice.rb +33 -0
  33. data/lib/activesupport-2.2.2/lib/active_support/vendor.rb +14 -0
  34. data/lib/activesupport-2.2.2/lib/active_support/vendor/builder-2.1.2/blankslate.rb +113 -0
  35. data/lib/activesupport-2.2.2/lib/active_support/vendor/builder-2.1.2/builder.rb +13 -0
  36. data/lib/activesupport-2.2.2/lib/active_support/vendor/builder-2.1.2/builder/blankslate.rb +20 -0
  37. data/lib/activesupport-2.2.2/lib/active_support/vendor/builder-2.1.2/builder/css.rb +250 -0
  38. data/lib/activesupport-2.2.2/lib/active_support/vendor/builder-2.1.2/builder/xchar.rb +115 -0
  39. data/lib/activesupport-2.2.2/lib/active_support/vendor/builder-2.1.2/builder/xmlbase.rb +139 -0
  40. data/lib/activesupport-2.2.2/lib/active_support/vendor/builder-2.1.2/builder/xmlevents.rb +63 -0
  41. data/lib/activesupport-2.2.2/lib/active_support/vendor/builder-2.1.2/builder/xmlmarkup.rb +328 -0
  42. data/lib/activesupport-2.2.2/lib/active_support/vendor/xml-simple-1.0.11/xmlsimple.rb +1021 -0
  43. data/lib/activesupport-2.2.2/lib/activesupport.rb +1 -0
  44. data/lib/esodclient/esodclient.rb +22 -0
  45. data/lib/hash.rb +22 -0
  46. data/lib/mime-types-1.16/History.txt +107 -0
  47. data/lib/mime-types-1.16/Install.txt +17 -0
  48. data/lib/mime-types-1.16/Licence.txt +15 -0
  49. data/lib/mime-types-1.16/Manifest.txt +12 -0
  50. data/lib/mime-types-1.16/README.txt +28 -0
  51. data/lib/mime-types-1.16/Rakefile +316 -0
  52. data/lib/mime-types-1.16/lib/mime/types.rb +751 -0
  53. data/lib/mime-types-1.16/lib/mime/types.rb.data +1324 -0
  54. data/lib/mime-types-1.16/mime-types.gemspec +43 -0
  55. data/lib/mime-types-1.16/setup.rb +1585 -0
  56. data/lib/mime-types-1.16/test/test_mime_type.rb +356 -0
  57. data/lib/mime-types-1.16/test/test_mime_types.rb +122 -0
  58. data/lib/rest-client-1.2.0/README.rdoc +102 -0
  59. data/lib/rest-client-1.2.0/Rakefile +57 -0
  60. data/lib/rest-client-1.2.0/VERSION +1 -0
  61. data/lib/rest-client-1.2.0/bin/restclient +87 -0
  62. data/lib/rest-client-1.2.0/lib/rest_client.rb +2 -0
  63. data/lib/rest-client-1.2.0/lib/restclient.rb +108 -0
  64. data/lib/rest-client-1.2.0/lib/restclient/exceptions.rb +89 -0
  65. data/lib/rest-client-1.2.0/lib/restclient/mixin/response.rb +48 -0
  66. data/lib/rest-client-1.2.0/lib/restclient/net_http_ext.rb +21 -0
  67. data/lib/rest-client-1.2.0/lib/restclient/payload.rb +178 -0
  68. data/lib/rest-client-1.2.0/lib/restclient/raw_response.rb +30 -0
  69. data/lib/rest-client-1.2.0/lib/restclient/request.rb +287 -0
  70. data/lib/rest-client-1.2.0/lib/restclient/resource.rb +146 -0
  71. data/lib/rest-client-1.2.0/lib/restclient/response.rb +20 -0
  72. data/lib/rest-client-1.2.0/spec/base.rb +10 -0
  73. data/lib/rest-client-1.2.0/spec/exceptions_spec.rb +65 -0
  74. data/lib/rest-client-1.2.0/spec/master_shake.jpg +0 -0
  75. data/lib/rest-client-1.2.0/spec/mixin/response_spec.rb +46 -0
  76. data/lib/rest-client-1.2.0/spec/payload_spec.rb +131 -0
  77. data/lib/rest-client-1.2.0/spec/raw_response_spec.rb +17 -0
  78. data/lib/rest-client-1.2.0/spec/request_spec.rb +521 -0
  79. data/lib/rest-client-1.2.0/spec/resource_spec.rb +75 -0
  80. data/lib/rest-client-1.2.0/spec/response_spec.rb +21 -0
  81. data/lib/rest-client-1.2.0/spec/restclient_spec.rb +53 -0
  82. data/lib/trollop/trollop.rb +735 -0
  83. metadata +137 -0
@@ -0,0 +1,75 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe RestClient::Resource do
4
+ before do
5
+ @resource = RestClient::Resource.new('http://some/resource', :user => 'jane', :password => 'mypass', :headers => { 'X-Something' => '1'})
6
+ end
7
+
8
+ context "Resource delegation" do
9
+ it "GET" do
10
+ RestClient::Request.should_receive(:execute).with(:method => :get, :url => 'http://some/resource', :headers => { 'X-Something' => '1'}, :user => 'jane', :password => 'mypass')
11
+ @resource.get
12
+ end
13
+
14
+ it "POST" do
15
+ RestClient::Request.should_receive(:execute).with(:method => :post, :url => 'http://some/resource', :payload => 'abc', :headers => { :content_type => 'image/jpg', 'X-Something' => '1'}, :user => 'jane', :password => 'mypass')
16
+ @resource.post 'abc', :content_type => 'image/jpg'
17
+ end
18
+
19
+ it "PUT" do
20
+ RestClient::Request.should_receive(:execute).with(:method => :put, :url => 'http://some/resource', :payload => 'abc', :headers => { :content_type => 'image/jpg', 'X-Something' => '1'}, :user => 'jane', :password => 'mypass')
21
+ @resource.put 'abc', :content_type => 'image/jpg'
22
+ end
23
+
24
+ it "DELETE" do
25
+ RestClient::Request.should_receive(:execute).with(:method => :delete, :url => 'http://some/resource', :headers => { 'X-Something' => '1'}, :user => 'jane', :password => 'mypass')
26
+ @resource.delete
27
+ end
28
+
29
+ it "overrides resource headers" do
30
+ RestClient::Request.should_receive(:execute).with(:method => :get, :url => 'http://some/resource', :headers => { 'X-Something' => '2'}, :user => 'jane', :password => 'mypass')
31
+ @resource.get 'X-Something' => '2'
32
+ end
33
+ end
34
+
35
+ it "can instantiate with no user/password" do
36
+ @resource = RestClient::Resource.new('http://some/resource')
37
+ end
38
+
39
+ it "is backwards compatible with previous constructor" do
40
+ @resource = RestClient::Resource.new('http://some/resource', 'user', 'pass')
41
+ @resource.user.should == 'user'
42
+ @resource.password.should == 'pass'
43
+ end
44
+
45
+ it "concatenates urls, inserting a slash when it needs one" do
46
+ @resource.concat_urls('http://example.com', 'resource').should == 'http://example.com/resource'
47
+ end
48
+
49
+ it "concatenates urls, using no slash if the first url ends with a slash" do
50
+ @resource.concat_urls('http://example.com/', 'resource').should == 'http://example.com/resource'
51
+ end
52
+
53
+ it "concatenates urls, using no slash if the second url starts with a slash" do
54
+ @resource.concat_urls('http://example.com', '/resource').should == 'http://example.com/resource'
55
+ end
56
+
57
+ it "concatenates even non-string urls, :posts + 1 => 'posts/1'" do
58
+ @resource.concat_urls(:posts, 1).should == 'posts/1'
59
+ end
60
+
61
+ it "offers subresources via []" do
62
+ parent = RestClient::Resource.new('http://example.com')
63
+ parent['posts'].url.should == 'http://example.com/posts'
64
+ end
65
+
66
+ it "transports options to subresources" do
67
+ parent = RestClient::Resource.new('http://example.com', :user => 'user', :password => 'password')
68
+ parent['posts'].user.should == 'user'
69
+ parent['posts'].password.should == 'password'
70
+ end
71
+
72
+ it "prints its url with to_s" do
73
+ RestClient::Resource.new('x').to_s.should == 'x'
74
+ end
75
+ end
@@ -0,0 +1,21 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe RestClient::Response do
4
+ before do
5
+ @net_http_res = mock('net http response', :to_hash => {"Status" => ["200 OK"]})
6
+ @response = RestClient::Response.new('abc', @net_http_res)
7
+ end
8
+
9
+ it "behaves like string" do
10
+ @response.should == 'abc'
11
+ end
12
+
13
+ it "accepts nil strings and sets it to empty for the case of HEAD" do
14
+ RestClient::Response.new(nil, @net_http_res).should == ""
15
+ end
16
+
17
+ it "test headers and raw headers" do
18
+ @response.raw_headers["Status"][0].should == "200 OK"
19
+ @response.headers[:status].should == "200 OK"
20
+ end
21
+ end
@@ -0,0 +1,53 @@
1
+ require File.dirname(__FILE__) + '/base'
2
+
3
+ describe RestClient do
4
+ describe "API" do
5
+ it "GET" do
6
+ RestClient::Request.should_receive(:execute).with(:method => :get, :url => 'http://some/resource', :headers => {})
7
+ RestClient.get('http://some/resource')
8
+ end
9
+
10
+ it "POST" do
11
+ RestClient::Request.should_receive(:execute).with(:method => :post, :url => 'http://some/resource', :payload => 'payload', :headers => {})
12
+ RestClient.post('http://some/resource', 'payload')
13
+ end
14
+
15
+ it "PUT" do
16
+ RestClient::Request.should_receive(:execute).with(:method => :put, :url => 'http://some/resource', :payload => 'payload', :headers => {})
17
+ RestClient.put('http://some/resource', 'payload')
18
+ end
19
+
20
+ it "DELETE" do
21
+ RestClient::Request.should_receive(:execute).with(:method => :delete, :url => 'http://some/resource', :headers => {})
22
+ RestClient.delete('http://some/resource')
23
+ end
24
+
25
+ it "HEAD" do
26
+ RestClient::Request.should_receive(:execute).with(:method => :head, :url => 'http://some/resource', :headers => {})
27
+ RestClient.head('http://some/resource')
28
+ end
29
+ end
30
+
31
+ describe "logging" do
32
+ after do
33
+ RestClient.log = nil
34
+ end
35
+
36
+ it "gets the log source from the RESTCLIENT_LOG environment variable" do
37
+ ENV.stub!(:[]).with('RESTCLIENT_LOG').and_return('from env')
38
+ RestClient.log = 'from class method'
39
+ RestClient.log.should == 'from env'
40
+ end
41
+
42
+ it "sets a destination for log output, used if no environment variable is set" do
43
+ ENV.stub!(:[]).with('RESTCLIENT_LOG').and_return(nil)
44
+ RestClient.log = 'from class method'
45
+ RestClient.log.should == 'from class method'
46
+ end
47
+
48
+ it "returns nil (no logging) if neither are set (default)" do
49
+ ENV.stub!(:[]).with('RESTCLIENT_LOG').and_return(nil)
50
+ RestClient.log.should == nil
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,735 @@
1
+ ## lib/trollop.rb -- trollop command-line processing library
2
+ ## Author:: William Morgan (mailto: wmorgan-trollop@masanjin.net)
3
+ ## Copyright:: Copyright 2007 William Morgan
4
+ ## License:: GNU GPL version 2
5
+
6
+ require 'date'
7
+
8
+ module Trollop
9
+
10
+ VERSION = "1.13"
11
+
12
+ ## Thrown by Parser in the event of a commandline error. Not needed if
13
+ ## you're using the Trollop::options entry.
14
+ class CommandlineError < StandardError; end
15
+
16
+ ## Thrown by Parser if the user passes in '-h' or '--help'. Handled
17
+ ## automatically by Trollop#options.
18
+ class HelpNeeded < StandardError; end
19
+
20
+ ## Thrown by Parser if the user passes in '-h' or '--version'. Handled
21
+ ## automatically by Trollop#options.
22
+ class VersionNeeded < StandardError; end
23
+
24
+ ## Regex for floating point numbers
25
+ FLOAT_RE = /^-?((\d+(\.\d+)?)|(\.\d+))$/
26
+
27
+ ## Regex for parameters
28
+ PARAM_RE = /^-(-|\.$|[^\d\.])/
29
+
30
+ ## The commandline parser. In typical usage, the methods in this class
31
+ ## will be handled internally by Trollop::options. In this case, only the
32
+ ## #opt, #banner and #version, #depends, and #conflicts methods will
33
+ ## typically be called.
34
+ ##
35
+ ## If it's necessary to instantiate this class (for more complicated
36
+ ## argument-parsing situations), be sure to call #parse to actually
37
+ ## produce the output hash.
38
+ class Parser
39
+
40
+ ## The set of values that indicate a flag option when passed as the
41
+ ## +:type+ parameter of #opt.
42
+ FLAG_TYPES = [:flag, :bool, :boolean]
43
+
44
+ ## The set of values that indicate a single-parameter option when
45
+ ## passed as the +:type+ parameter of #opt.
46
+ ##
47
+ ## A value of +io+ corresponds to a readable IO resource, including
48
+ ## a filename, URI, or the strings 'stdin' or '-'.
49
+ SINGLE_ARG_TYPES = [:int, :integer, :string, :double, :float, :io, :date]
50
+
51
+ ## The set of values that indicate a multiple-parameter option when
52
+ ## passed as the +:type+ parameter of #opt.
53
+ MULTI_ARG_TYPES = [:ints, :integers, :strings, :doubles, :floats, :ios, :dates]
54
+
55
+ ## The complete set of legal values for the +:type+ parameter of #opt.
56
+ TYPES = FLAG_TYPES + SINGLE_ARG_TYPES + MULTI_ARG_TYPES
57
+
58
+ INVALID_SHORT_ARG_REGEX = /[\d-]/ #:nodoc:
59
+
60
+ ## The values from the commandline that were not interpreted by #parse.
61
+ attr_reader :leftovers
62
+
63
+ ## The complete configuration hashes for each option. (Mainly useful
64
+ ## for testing.)
65
+ attr_reader :specs
66
+
67
+ ## Initializes the parser, and instance-evaluates any block given.
68
+ def initialize *a, &b
69
+ @version = nil
70
+ @leftovers = []
71
+ @specs = {}
72
+ @long = {}
73
+ @short = {}
74
+ @order = []
75
+ @constraints = []
76
+ @stop_words = []
77
+ @stop_on_unknown = false
78
+
79
+ #instance_eval(&b) if b # can't take arguments
80
+ cloaker(&b).bind(self).call(*a) if b
81
+ end
82
+
83
+ ## Define an option. +name+ is the option name, a unique identifier
84
+ ## for the option that you will use internally, which should be a
85
+ ## symbol or a string. +desc+ is a string description which will be
86
+ ## displayed in help messages.
87
+ ##
88
+ ## Takes the following optional arguments:
89
+ ##
90
+ ## [+:long+] Specify the long form of the argument, i.e. the form with two dashes. If unspecified, will be automatically derived based on the argument name by turning the +name+ option into a string, and replacing any _'s by -'s.
91
+ ## [+:short+] Specify the short form of the argument, i.e. the form with one dash. If unspecified, will be automatically derived from +name+.
92
+ ## [+:type+] Require that the argument take a parameter or parameters of type +type+. For a single parameter, the value can be a member of +SINGLE_ARG_TYPES+, or a corresponding Ruby class (e.g. +Integer+ for +:int+). For multiple-argument parameters, the value can be any member of +MULTI_ARG_TYPES+ constant. If unset, the default argument type is +:flag+, meaning that the argument does not take a parameter. The specification of +:type+ is not necessary if a +:default+ is given.
93
+ ## [+:default+] Set the default value for an argument. Without a default value, the hash returned by #parse (and thus Trollop::options) will have a +nil+ value for this key unless the argument is given on the commandline. The argument type is derived automatically from the class of the default value given, so specifying a +:type+ is not necessary if a +:default+ is given. (But see below for an important caveat when +:multi+: is specified too.) If the argument is a flag, and the default is set to +true+, then if it is specified on the the commandline the value will be +false+.
94
+ ## [+:required+] If set to +true+, the argument must be provided on the commandline.
95
+ ## [+:multi+] If set to +true+, allows multiple occurrences of the option on the commandline. Otherwise, only a single instance of the option is allowed. (Note that this is different from taking multiple parameters. See below.)
96
+ ##
97
+ ## Note that there are two types of argument multiplicity: an argument
98
+ ## can take multiple values, e.g. "--arg 1 2 3". An argument can also
99
+ ## be allowed to occur multiple times, e.g. "--arg 1 --arg 2".
100
+ ##
101
+ ## Arguments that take multiple values should have a +:type+ parameter
102
+ ## drawn from +MULTI_ARG_TYPES+ (e.g. +:strings+), or a +:default:+
103
+ ## value of an array of the correct type (e.g. [String]). The
104
+ ## value of this argument will be an array of the parameters on the
105
+ ## commandline.
106
+ ##
107
+ ## Arguments that can occur multiple times should be marked with
108
+ ## +:multi+ => +true+. The value of this argument will also be an array.
109
+ ##
110
+ ## These two attributes can be combined (e.g. +:type+ => +:strings+,
111
+ ## +:multi+ => +true+), in which case the value of the argument will be
112
+ ## an array of arrays.
113
+ ##
114
+ ## There's one ambiguous case to be aware of: when +:multi+: is true and a
115
+ ## +:default+ is set to an array (of something), it's ambiguous whether this
116
+ ## is a multi-value argument as well as a multi-occurrence argument.
117
+ ## In thise case, Trollop assumes that it's not a multi-value argument.
118
+ ## If you want a multi-value, multi-occurrence argument with a default
119
+ ## value, you must specify +:type+ as well.
120
+
121
+ def opt name, desc="", opts={}
122
+ raise ArgumentError, "you already have an argument named '#{name}'" if @specs.member? name
123
+
124
+ ## fill in :type
125
+ opts[:type] = # normalize
126
+ case opts[:type]
127
+ when :boolean, :bool; :flag
128
+ when :integer; :int
129
+ when :integers; :ints
130
+ when :double; :float
131
+ when :doubles; :floats
132
+ when Class
133
+ case opts[:type].name
134
+ when 'TrueClass', 'FalseClass'; :flag
135
+ when 'String'; :string
136
+ when 'Integer'; :int
137
+ when 'Float'; :float
138
+ when 'IO'; :io
139
+ when 'Date'; :date
140
+ else
141
+ raise ArgumentError, "unsupported argument type '#{opts[:type].class.name}'"
142
+ end
143
+ when nil; nil
144
+ else
145
+ raise ArgumentError, "unsupported argument type '#{opts[:type]}'" unless TYPES.include?(opts[:type])
146
+ opts[:type]
147
+ end
148
+
149
+ ## for options with :multi => true, an array default doesn't imply
150
+ ## a multi-valued argument. for that you have to specify a :type
151
+ ## as well. (this is how we disambiguate an ambiguous situation;
152
+ ## see the docs for Parser#opt for details.)
153
+ disambiguated_default =
154
+ if opts[:multi] && opts[:default].is_a?(Array) && !opts[:type]
155
+ opts[:default].first
156
+ else
157
+ opts[:default]
158
+ end
159
+
160
+ type_from_default =
161
+ case disambiguated_default
162
+ when Integer; :int
163
+ when Numeric; :float
164
+ when TrueClass, FalseClass; :flag
165
+ when String; :string
166
+ when IO; :io
167
+ when Date; :date
168
+ when Array
169
+ if opts[:default].empty?
170
+ raise ArgumentError, "multiple argument type cannot be deduced from an empty array for '#{opts[:default][0].class.name}'"
171
+ end
172
+ case opts[:default][0] # the first element determines the types
173
+ when Integer; :ints
174
+ when Numeric; :floats
175
+ when String; :strings
176
+ when IO; :ios
177
+ when Date; :dates
178
+ else
179
+ raise ArgumentError, "unsupported multiple argument type '#{opts[:default][0].class.name}'"
180
+ end
181
+ when nil; nil
182
+ else
183
+ raise ArgumentError, "unsupported argument type '#{opts[:default].class.name}'"
184
+ end
185
+
186
+ raise ArgumentError, ":type specification and default type don't match" if opts[:type] && type_from_default && opts[:type] != type_from_default
187
+
188
+ opts[:type] = opts[:type] || type_from_default || :flag
189
+
190
+ ## fill in :long
191
+ opts[:long] = opts[:long] ? opts[:long].to_s : name.to_s.gsub("_", "-")
192
+ opts[:long] =
193
+ case opts[:long]
194
+ when /^--([^-].*)$/
195
+ $1
196
+ when /^[^-]/
197
+ opts[:long]
198
+ else
199
+ raise ArgumentError, "invalid long option name #{opts[:long].inspect}"
200
+ end
201
+ raise ArgumentError, "long option name #{opts[:long].inspect} is already taken; please specify a (different) :long" if @long[opts[:long]]
202
+
203
+ ## fill in :short
204
+ opts[:short] = opts[:short].to_s if opts[:short] unless opts[:short] == :none
205
+ opts[:short] = case opts[:short]
206
+ when /^-(.)$/; $1
207
+ when nil, :none, /^.$/; opts[:short]
208
+ else raise ArgumentError, "invalid short option name '#{opts[:short].inspect}'"
209
+ end
210
+
211
+ if opts[:short]
212
+ raise ArgumentError, "short option name #{opts[:short].inspect} is already taken; please specify a (different) :short" if @short[opts[:short]]
213
+ raise ArgumentError, "a short option name can't be a number or a dash" if opts[:short] =~ INVALID_SHORT_ARG_REGEX
214
+ end
215
+
216
+ ## fill in :default for flags
217
+ opts[:default] = false if opts[:type] == :flag && opts[:default].nil?
218
+
219
+ ## autobox :default for :multi (multi-occurrence) arguments
220
+ opts[:default] = [opts[:default]] if opts[:default] && opts[:multi] && !opts[:default].is_a?(Array)
221
+
222
+ ## fill in :multi
223
+ opts[:multi] ||= false
224
+
225
+ opts[:desc] ||= desc
226
+ @long[opts[:long]] = name
227
+ @short[opts[:short]] = name if opts[:short] && opts[:short] != :none
228
+ @specs[name] = opts
229
+ @order << [:opt, name]
230
+ end
231
+
232
+ ## Sets the version string. If set, the user can request the version
233
+ ## on the commandline. Should probably be of the form "<program name>
234
+ ## <version number>".
235
+ def version s=nil; @version = s if s; @version end
236
+
237
+ ## Adds text to the help display. Can be interspersed with calls to
238
+ ## #opt to build a multi-section help page.
239
+ def banner s; @order << [:text, s] end
240
+ alias :text :banner
241
+
242
+ ## Marks two (or more!) options as requiring each other. Only handles
243
+ ## undirected (i.e., mutual) dependencies. Directed dependencies are
244
+ ## better modeled with Trollop::die.
245
+ def depends *syms
246
+ syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] }
247
+ @constraints << [:depends, syms]
248
+ end
249
+
250
+ ## Marks two (or more!) options as conflicting.
251
+ def conflicts *syms
252
+ syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] }
253
+ @constraints << [:conflicts, syms]
254
+ end
255
+
256
+ ## Defines a set of words which cause parsing to terminate when
257
+ ## encountered, such that any options to the left of the word are
258
+ ## parsed as usual, and options to the right of the word are left
259
+ ## intact.
260
+ ##
261
+ ## A typical use case would be for subcommand support, where these
262
+ ## would be set to the list of subcommands. A subsequent Trollop
263
+ ## invocation would then be used to parse subcommand options, after
264
+ ## shifting the subcommand off of ARGV.
265
+ def stop_on *words
266
+ @stop_words = [*words].flatten
267
+ end
268
+
269
+ ## Similar to #stop_on, but stops on any unknown word when encountered
270
+ ## (unless it is a parameter for an argument). This is useful for
271
+ ## cases where you don't know the set of subcommands ahead of time,
272
+ ## i.e., without first parsing the global options.
273
+ def stop_on_unknown
274
+ @stop_on_unknown = true
275
+ end
276
+
277
+ ## Parses the commandline. Typically called by Trollop::options.
278
+ def parse cmdline=ARGV
279
+ vals = {}
280
+ required = {}
281
+
282
+ opt :version, "Print version and exit" if @version unless @specs[:version] || @long["version"]
283
+ opt :help, "Show this message" unless @specs[:help] || @long["help"]
284
+
285
+ @specs.each do |sym, opts|
286
+ required[sym] = true if opts[:required]
287
+ vals[sym] = opts[:default]
288
+ end
289
+
290
+ resolve_default_short_options
291
+
292
+ ## resolve symbols
293
+ given_args = {}
294
+ @leftovers = each_arg cmdline do |arg, params|
295
+ sym = case arg
296
+ when /^-([^-])$/
297
+ @short[$1]
298
+ when /^--([^-]\S*)$/
299
+ @long[$1]
300
+ else
301
+ raise CommandlineError, "invalid argument syntax: '#{arg}'"
302
+ end
303
+ raise CommandlineError, "unknown argument '#{arg}'" unless sym
304
+
305
+ if given_args.include?(sym) && !@specs[sym][:multi]
306
+ raise CommandlineError, "option '#{arg}' specified multiple times"
307
+ end
308
+
309
+ given_args[sym] ||= {}
310
+
311
+ given_args[sym][:arg] = arg
312
+ given_args[sym][:params] ||= []
313
+
314
+ # The block returns the number of parameters taken.
315
+ num_params_taken = 0
316
+
317
+ unless params.nil?
318
+ if SINGLE_ARG_TYPES.include?(@specs[sym][:type])
319
+ given_args[sym][:params] << params[0, 1] # take the first parameter
320
+ num_params_taken = 1
321
+ elsif MULTI_ARG_TYPES.include?(@specs[sym][:type])
322
+ given_args[sym][:params] << params # take all the parameters
323
+ num_params_taken = params.size
324
+ end
325
+ end
326
+
327
+ num_params_taken
328
+ end
329
+
330
+ ## check for version and help args
331
+ raise VersionNeeded if given_args.include? :version
332
+ raise HelpNeeded if given_args.include? :help
333
+
334
+ ## check constraint satisfaction
335
+ @constraints.each do |type, syms|
336
+ constraint_sym = syms.find { |sym| given_args[sym] }
337
+ next unless constraint_sym
338
+
339
+ case type
340
+ when :depends
341
+ syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym][:long]} requires --#{@specs[sym][:long]}" unless given_args.include? sym }
342
+ when :conflicts
343
+ syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym][:long]} conflicts with --#{@specs[sym][:long]}" if given_args.include?(sym) && (sym != constraint_sym) }
344
+ end
345
+ end
346
+
347
+ required.each do |sym, val|
348
+ raise CommandlineError, "option '#{sym}' must be specified" unless given_args.include? sym
349
+ end
350
+
351
+ ## parse parameters
352
+ given_args.each do |sym, given_data|
353
+ arg = given_data[:arg]
354
+ params = given_data[:params]
355
+
356
+ opts = @specs[sym]
357
+ raise CommandlineError, "option '#{arg}' needs a parameter" if params.empty? && opts[:type] != :flag
358
+
359
+ vals["#{sym}_given".intern] = true # mark argument as specified on the commandline
360
+
361
+ case opts[:type]
362
+ when :flag
363
+ vals[sym] = !opts[:default]
364
+ when :int, :ints
365
+ vals[sym] = params.map { |pg| pg.map { |p| parse_integer_parameter p, arg } }
366
+ when :float, :floats
367
+ vals[sym] = params.map { |pg| pg.map { |p| parse_float_parameter p, arg } }
368
+ when :string, :strings
369
+ vals[sym] = params.map { |pg| pg.map { |p| p.to_s } }
370
+ when :io, :ios
371
+ vals[sym] = params.map { |pg| pg.map { |p| parse_io_parameter p, arg } }
372
+ when :date, :dates
373
+ vals[sym] = params.map { |pg| pg.map { |p| parse_date_parameter p, arg } }
374
+ end
375
+
376
+ if SINGLE_ARG_TYPES.include?(opts[:type])
377
+ unless opts[:multi] # single parameter
378
+ vals[sym] = vals[sym][0][0]
379
+ else # multiple options, each with a single parameter
380
+ vals[sym] = vals[sym].map { |p| p[0] }
381
+ end
382
+ elsif MULTI_ARG_TYPES.include?(opts[:type]) && !opts[:multi]
383
+ vals[sym] = vals[sym][0] # single option, with multiple parameters
384
+ end
385
+ # else: multiple options, with multiple parameters
386
+ end
387
+
388
+ ## allow openstruct-style accessors
389
+ class << vals
390
+ def method_missing(m, *args)
391
+ self[m] || self[m.to_s]
392
+ end
393
+ end
394
+ vals
395
+ end
396
+
397
+ def parse_date_parameter param, arg #:nodoc:
398
+ begin
399
+ begin
400
+ time = Chronic.parse(param)
401
+ rescue NameError
402
+ # chronic is not available
403
+ end
404
+ time ? Date.new(time.year, time.month, time.day) : Date.parse(param)
405
+ rescue ArgumentError => e
406
+ raise CommandlineError, "option '#{arg}' needs a date"
407
+ end
408
+ end
409
+
410
+ ## Print the help message to +stream+.
411
+ def educate stream=$stdout
412
+ width # just calculate it now; otherwise we have to be careful not to
413
+ # call this unless the cursor's at the beginning of a line.
414
+
415
+ left = {}
416
+ @specs.each do |name, spec|
417
+ left[name] = "--#{spec[:long]}" +
418
+ (spec[:short] && spec[:short] != :none ? ", -#{spec[:short]}" : "") +
419
+ case spec[:type]
420
+ when :flag; ""
421
+ when :int; " <i>"
422
+ when :ints; " <i+>"
423
+ when :string; " <s>"
424
+ when :strings; " <s+>"
425
+ when :float; " <f>"
426
+ when :floats; " <f+>"
427
+ when :io; " <filename/uri>"
428
+ when :ios; " <filename/uri+>"
429
+ when :date; " <date>"
430
+ when :dates; " <date+>"
431
+ end
432
+ end
433
+
434
+ leftcol_width = left.values.map { |s| s.length }.max || 0
435
+ rightcol_start = leftcol_width + 6 # spaces
436
+
437
+ unless @order.size > 0 && @order.first.first == :text
438
+ stream.puts "#@version\n" if @version
439
+ stream.puts "Options:"
440
+ end
441
+
442
+ @order.each do |what, opt|
443
+ if what == :text
444
+ stream.puts wrap(opt)
445
+ next
446
+ end
447
+
448
+ spec = @specs[opt]
449
+ stream.printf " %#{leftcol_width}s: ", left[opt]
450
+ desc = spec[:desc] + begin
451
+ default_s = case spec[:default]
452
+ when $stdout; "<stdout>"
453
+ when $stdin; "<stdin>"
454
+ when $stderr; "<stderr>"
455
+ when Array
456
+ spec[:default].join(", ")
457
+ else
458
+ spec[:default].to_s
459
+ end
460
+
461
+ if spec[:default]
462
+ if spec[:desc] =~ /\.$/
463
+ " (Default: #{default_s})"
464
+ else
465
+ " (default: #{default_s})"
466
+ end
467
+ else
468
+ ""
469
+ end
470
+ end
471
+ stream.puts wrap(desc, :width => width - rightcol_start - 1, :prefix => rightcol_start)
472
+ end
473
+ end
474
+
475
+ def width #:nodoc:
476
+ @width ||= if $stdout.tty?
477
+ begin
478
+ require 'curses'
479
+ Curses::init_screen
480
+ x = Curses::cols
481
+ Curses::close_screen
482
+ x
483
+ rescue Exception
484
+ 80
485
+ end
486
+ else
487
+ 80
488
+ end
489
+ end
490
+
491
+ def wrap str, opts={} # :nodoc:
492
+ if str == ""
493
+ [""]
494
+ else
495
+ str.split("\n").map { |s| wrap_line s, opts }.flatten
496
+ end
497
+ end
498
+
499
+ private
500
+
501
+ ## yield successive arg, parameter pairs
502
+ def each_arg args
503
+ remains = []
504
+ i = 0
505
+
506
+ until i >= args.length
507
+ if @stop_words.member? args[i]
508
+ remains += args[i .. -1]
509
+ return remains
510
+ end
511
+ case args[i]
512
+ when /^--$/ # arg terminator
513
+ remains += args[(i + 1) .. -1]
514
+ return remains
515
+ when /^--(\S+?)=(.*)$/ # long argument with equals
516
+ yield "--#{$1}", [$2]
517
+ i += 1
518
+ when /^--(\S+)$/ # long argument
519
+ params = collect_argument_parameters(args, i + 1)
520
+ unless params.empty?
521
+ num_params_taken = yield args[i], params
522
+ unless num_params_taken
523
+ if @stop_on_unknown
524
+ remains += args[i + 1 .. -1]
525
+ return remains
526
+ else
527
+ remains += params
528
+ end
529
+ end
530
+ i += 1 + num_params_taken
531
+ else # long argument no parameter
532
+ yield args[i], nil
533
+ i += 1
534
+ end
535
+ when /^-(\S+)$/ # one or more short arguments
536
+ shortargs = $1.split(//)
537
+ shortargs.each_with_index do |a, j|
538
+ if j == (shortargs.length - 1)
539
+ params = collect_argument_parameters(args, i + 1)
540
+ unless params.empty?
541
+ num_params_taken = yield "-#{a}", params
542
+ unless num_params_taken
543
+ if @stop_on_unknown
544
+ remains += args[i + 1 .. -1]
545
+ return remains
546
+ else
547
+ remains += params
548
+ end
549
+ end
550
+ i += 1 + num_params_taken
551
+ else # argument no parameter
552
+ yield "-#{a}", nil
553
+ i += 1
554
+ end
555
+ else
556
+ yield "-#{a}", nil
557
+ end
558
+ end
559
+ else
560
+ if @stop_on_unknown
561
+ remains += args[i .. -1]
562
+ return remains
563
+ else
564
+ remains << args[i]
565
+ i += 1
566
+ end
567
+ end
568
+ end
569
+
570
+ remains
571
+ end
572
+
573
+ def parse_integer_parameter param, arg
574
+ raise CommandlineError, "option '#{arg}' needs an integer" unless param =~ /^\d+$/
575
+ param.to_i
576
+ end
577
+
578
+ def parse_float_parameter param, arg
579
+ raise CommandlineError, "option '#{arg}' needs a floating-point number" unless param =~ FLOAT_RE
580
+ param.to_f
581
+ end
582
+
583
+ def parse_io_parameter param, arg
584
+ case param
585
+ when /^(stdin|-)$/i; $stdin
586
+ else
587
+ require 'open-uri'
588
+ begin
589
+ open param
590
+ rescue SystemCallError => e
591
+ raise CommandlineError, "file or url for option '#{arg}' cannot be opened: #{e.message}"
592
+ end
593
+ end
594
+ end
595
+
596
+ def collect_argument_parameters args, start_at
597
+ params = []
598
+ pos = start_at
599
+ while args[pos] && args[pos] !~ PARAM_RE && !@stop_words.member?(args[pos]) do
600
+ params << args[pos]
601
+ pos += 1
602
+ end
603
+ params
604
+ end
605
+
606
+ def resolve_default_short_options
607
+ @order.each do |type, name|
608
+ next unless type == :opt
609
+ opts = @specs[name]
610
+ next if opts[:short]
611
+
612
+ c = opts[:long].split(//).find { |d| d !~ INVALID_SHORT_ARG_REGEX && !@short.member?(d) }
613
+ raise ArgumentError, "can't generate a default short option name for #{opts[:long].inspect}: out of unique characters" unless c
614
+
615
+ opts[:short] = c
616
+ @short[c] = name
617
+ end
618
+ end
619
+
620
+ def wrap_line str, opts={}
621
+ prefix = opts[:prefix] || 0
622
+ width = opts[:width] || (self.width - 1)
623
+ start = 0
624
+ ret = []
625
+ until start > str.length
626
+ nextt =
627
+ if start + width >= str.length
628
+ str.length
629
+ else
630
+ x = str.rindex(/\s/, start + width)
631
+ x = str.index(/\s/, start) if x && x < start
632
+ x || str.length
633
+ end
634
+ ret << (ret.empty? ? "" : " " * prefix) + str[start ... nextt]
635
+ start = nextt + 1
636
+ end
637
+ ret
638
+ end
639
+
640
+ ## instance_eval but with ability to handle block arguments
641
+ ## thanks to why: http://redhanded.hobix.com/inspect/aBlockCostume.html
642
+ def cloaker &b
643
+ (class << self; self; end).class_eval do
644
+ define_method :cloaker_, &b
645
+ meth = instance_method :cloaker_
646
+ remove_method :cloaker_
647
+ meth
648
+ end
649
+ end
650
+ end
651
+
652
+ ## The top-level entry method into Trollop. Creates a Parser object,
653
+ ## passes the block to it, then parses +args+ with it, handling any
654
+ ## errors or requests for help or version information appropriately (and
655
+ ## then exiting). Modifies +args+ in place. Returns a hash of option
656
+ ## values.
657
+ ##
658
+ ## The block passed in should contain zero or more calls to +opt+
659
+ ## (Parser#opt), zero or more calls to +text+ (Parser#text), and
660
+ ## probably a call to +version+ (Parser#version).
661
+ ##
662
+ ## The returned block contains a value for every option specified with
663
+ ## +opt+. The value will be the value given on the commandline, or the
664
+ ## default value if the option was not specified on the commandline. For
665
+ ## every option specified on the commandline, a key "<option
666
+ ## name>_given" will also be set in the hash.
667
+ ##
668
+ ## Example:
669
+ ##
670
+ ## require 'trollop'
671
+ ## opts = Trollop::options do
672
+ ## opt :monkey, "Use monkey mode" # a flag --monkey, defaulting to false
673
+ ## opt :goat, "Use goat mode", :default => true # a flag --goat, defaulting to true
674
+ ## opt :num_limbs, "Number of limbs", :default => 4 # an integer --num-limbs <i>, defaulting to 4
675
+ ## opt :num_thumbs, "Number of thumbs", :type => :int # an integer --num-thumbs <i>, defaulting to nil
676
+ ## end
677
+ ##
678
+ ## ## if called with no arguments
679
+ ## p opts # => { :monkey => false, :goat => true, :num_limbs => 4, :num_thumbs => nil }
680
+ ##
681
+ ## ## if called with --monkey
682
+ ## p opts # => {:monkey_given=>true, :monkey=>true, :goat=>true, :num_limbs=>4, :help=>false, :num_thumbs=>nil}
683
+ ##
684
+ ## See more examples at http://trollop.rubyforge.org.
685
+ def options args = ARGV, *a, &b
686
+ @p = Parser.new(*a, &b)
687
+ begin
688
+ vals = @p.parse args
689
+ args.clear
690
+ @p.leftovers.each { |l| args << l }
691
+ vals
692
+ rescue CommandlineError => e
693
+ $stderr.puts "Error: #{e.message}."
694
+ $stderr.puts "Try --help for help."
695
+ exit(-1)
696
+ rescue HelpNeeded
697
+ @p.educate
698
+ exit
699
+ rescue VersionNeeded
700
+ puts @p.version
701
+ exit
702
+ end
703
+ end
704
+
705
+ ## Informs the user that their usage of 'arg' was wrong, as detailed by
706
+ ## 'msg', and dies. Example:
707
+ ##
708
+ ## options do
709
+ ## opt :volume, :default => 0.0
710
+ ## end
711
+ ##
712
+ ## die :volume, "too loud" if opts[:volume] > 10.0
713
+ ## die :volume, "too soft" if opts[:volume] < 0.1
714
+ ##
715
+ ## In the one-argument case, simply print that message, a notice
716
+ ## about -h, and die. Example:
717
+ ##
718
+ ## options do
719
+ ## opt :whatever # ...
720
+ ## end
721
+ ##
722
+ ## Trollop::die "need at least one filename" if ARGV.empty?
723
+ def die arg, msg=nil
724
+ if msg
725
+ $stderr.puts "Error: argument --#{@p.specs[arg][:long]} #{msg}."
726
+ else
727
+ $stderr.puts "Error: #{arg}."
728
+ end
729
+ $stderr.puts "Try --help for help."
730
+ exit(-1)
731
+ end
732
+
733
+ module_function :options, :die
734
+
735
+ end # module