appsendr 0.0.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.
- data/Manifest +0 -0
- data/README.rdoc +50 -0
- data/Rakefile +16 -0
- data/appsendr.gemspec +41 -0
- data/bin/appsendr +14 -0
- data/lib/appsendr/binary_plist.rb +514 -0
- data/lib/appsendr/client.rb +115 -0
- data/lib/appsendr/command.rb +68 -0
- data/lib/appsendr/commands/app.rb +167 -0
- data/lib/appsendr/commands/auth.rb +155 -0
- data/lib/appsendr/commands/base.rb +63 -0
- data/lib/appsendr/commands/build.rb +198 -0
- data/lib/appsendr/commands/deploy.rb +41 -0
- data/lib/appsendr/commands/help.rb +87 -0
- data/lib/appsendr/commands/testers.rb +115 -0
- data/lib/appsendr/commands/version.rb +7 -0
- data/lib/appsendr/constants.rb +5 -0
- data/lib/appsendr/helpers.rb +120 -0
- data/lib/appsendr.rb +3 -0
- metadata +151 -0
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rest_client'
|
3
|
+
require 'uri'
|
4
|
+
require 'time'
|
5
|
+
require 'appsendr/constants'
|
6
|
+
require 'json/pure' unless {}.respond_to?(:to_json)
|
7
|
+
|
8
|
+
# A Ruby class to call the Heroku REST API. You might use this if you want to
|
9
|
+
# manage your Heroku apps from within a Ruby program, such as Capistrano.
|
10
|
+
#
|
11
|
+
# Example:
|
12
|
+
#
|
13
|
+
# require 'appsendr'
|
14
|
+
# droppr = AppSendr::Client.new('me@example.com', 'mypass')
|
15
|
+
# droppr.create('myapp')
|
16
|
+
#
|
17
|
+
class AppSendr::Client
|
18
|
+
def self.version
|
19
|
+
AppSendr::VERSION
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.gem_version_string
|
23
|
+
"appsendr-gem/#{version}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.auth(user,pass,host)
|
27
|
+
@resource = RestClient::Resource.new "http://#{host}"
|
28
|
+
resp = @resource['/api/user/authenticate'].post({:username=>user, :password=>pass})
|
29
|
+
json_resp = JSON.parse(resp)
|
30
|
+
return nil unless json_resp
|
31
|
+
return json_resp["message"] if json_resp["status"].to_i == 200
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_reader :host, :user, :password, :api_key
|
36
|
+
|
37
|
+
def initialize(api_key,host='appsendr.com')
|
38
|
+
@api_key = api_key
|
39
|
+
@host = host
|
40
|
+
@resource = RestClient::Resource.new "http://#{@host}"
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
def authenticate
|
45
|
+
post('/api/user/authenticate');
|
46
|
+
end
|
47
|
+
|
48
|
+
def list
|
49
|
+
JSON.parse(get('/api/app/list'))
|
50
|
+
end
|
51
|
+
|
52
|
+
def link(id)
|
53
|
+
post('/api/app/link',{:id=>id});
|
54
|
+
end
|
55
|
+
|
56
|
+
def create(name)
|
57
|
+
JSON.parse(post('/api/app/create', {:name=>name}))
|
58
|
+
end
|
59
|
+
|
60
|
+
def add_tester(app_id,email,name,udid=nil)
|
61
|
+
post('/api/app/add_tester/'+app_id.to_s,{:email=>email, :name=>name});
|
62
|
+
end
|
63
|
+
|
64
|
+
def remove_tester(app_id,email)
|
65
|
+
post('/api/app/remove_tester/'+app_id.to_s,{:email=>email});
|
66
|
+
end
|
67
|
+
|
68
|
+
def clear_testers(app_id)
|
69
|
+
delete('/api/app/clear_testers/'+app_id.to_s,{});
|
70
|
+
end
|
71
|
+
|
72
|
+
def testers(app_id)
|
73
|
+
JSON.parse(get('/api/app/testers/'+app_id.to_s))
|
74
|
+
end
|
75
|
+
def notify(app_id)
|
76
|
+
JSON.parse(get('/api/app/notify/'+app_id.to_s))
|
77
|
+
end
|
78
|
+
|
79
|
+
def upload(app_id, ipa,provisioning, notes, bundle_id, icon)
|
80
|
+
params = {
|
81
|
+
:ipa => File.new(ipa, 'rb'),
|
82
|
+
:profile => File.new(provisioning, 'rb'),
|
83
|
+
:notes=>notes,
|
84
|
+
:bundle_identifier => bundle_id,
|
85
|
+
:built_at=>Time.now
|
86
|
+
}
|
87
|
+
if icon
|
88
|
+
params[:icon] = File.new(icon,'rb')
|
89
|
+
end
|
90
|
+
post('/api/app/upload/'+app_id.to_s, params)
|
91
|
+
end
|
92
|
+
|
93
|
+
protected
|
94
|
+
|
95
|
+
def api_params(params={})
|
96
|
+
params[:api_key] ||= @api_key
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
def get(uri,params={})
|
101
|
+
params[:api_key] ||= @api_key
|
102
|
+
RestClient.get @resource.url+uri, {:params=>params}
|
103
|
+
#@resource[uri].get(api_params(params))#, :content_type => 'application/json')
|
104
|
+
end
|
105
|
+
def post(uri,params={})
|
106
|
+
params[:api_key] ||= @api_key
|
107
|
+
@resource[uri].post(params)#, :content_type => 'application/json')
|
108
|
+
end
|
109
|
+
|
110
|
+
def delete(uri,params={})
|
111
|
+
params[:api_key] ||= @api_key
|
112
|
+
print params
|
113
|
+
@resource[uri].delete(params)#, :content_type => 'application/json')
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'appsendr/helpers'
|
2
|
+
require 'appsendr/binary_plist'
|
3
|
+
require 'appsendr/commands/base'
|
4
|
+
|
5
|
+
Dir["#{File.dirname(__FILE__)}/commands/*.rb"].each { |c| require c }
|
6
|
+
|
7
|
+
module AppSendr
|
8
|
+
module Command
|
9
|
+
class InvalidCommand < RuntimeError; end
|
10
|
+
class CommandFailed < RuntimeError; end
|
11
|
+
|
12
|
+
extend AppSendr::Helpers
|
13
|
+
|
14
|
+
class << self
|
15
|
+
|
16
|
+
def run(command, args, retries=0)
|
17
|
+
begin
|
18
|
+
run_internal 'auth:reauthorize', args.dup if (retries > 0 or !credentials_setup?)
|
19
|
+
run_internal(command, args.dup)
|
20
|
+
rescue InvalidCommand
|
21
|
+
error "Unknown command. Run 'appsendr help' for usage information."
|
22
|
+
rescue RestClient::Unauthorized
|
23
|
+
if retries < 3
|
24
|
+
STDERR.puts "Authentication failure"
|
25
|
+
run(command, args, retries+1)
|
26
|
+
else
|
27
|
+
error "Authentication failure"
|
28
|
+
end
|
29
|
+
rescue RestClient::RequestFailed
|
30
|
+
error "Something went wrong with the server."
|
31
|
+
rescue CommandFailed => e
|
32
|
+
error e.message
|
33
|
+
rescue Interrupt => e
|
34
|
+
error "\n[canceled]"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def run_internal(command, args, appsendr=nil)
|
39
|
+
klass, method = parse(command)
|
40
|
+
runner = klass.new(args, appsendr)
|
41
|
+
raise InvalidCommand unless runner.respond_to?(method)
|
42
|
+
runner.send(method)
|
43
|
+
end
|
44
|
+
|
45
|
+
def parse(command)
|
46
|
+
parts = command.split(':')
|
47
|
+
case parts.size
|
48
|
+
when 1
|
49
|
+
begin
|
50
|
+
return eval("AppSendr::Command::#{command.capitalize}"), :index
|
51
|
+
rescue NameError, NoMethodError
|
52
|
+
return AppSendr::Command::App, command.to_sym
|
53
|
+
end
|
54
|
+
else
|
55
|
+
begin
|
56
|
+
const = AppSendr::Command
|
57
|
+
command = parts.pop
|
58
|
+
parts.each { |part| const = const.const_get(part.capitalize) }
|
59
|
+
return const, command.to_sym
|
60
|
+
rescue NameError
|
61
|
+
raise InvalidCommand
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'readline'
|
2
|
+
#require 'launchy'
|
3
|
+
|
4
|
+
module AppSendr::Command
|
5
|
+
class App < Base
|
6
|
+
attr_accessor :app_id, :app_name, :app
|
7
|
+
|
8
|
+
def list
|
9
|
+
list = appsendr.list
|
10
|
+
if list["message"].size > 0
|
11
|
+
display "=== Your apps"
|
12
|
+
i = 0
|
13
|
+
display list["message"].map {|app, id|
|
14
|
+
"#{i+=1}. #{app['app']['name'].ljust(35)}"
|
15
|
+
}.join("\n")
|
16
|
+
else
|
17
|
+
display "You have no apps."
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def create
|
22
|
+
# username = extract_option('--username')
|
23
|
+
# display username
|
24
|
+
# password = extract_option('--password')
|
25
|
+
# display password
|
26
|
+
#
|
27
|
+
|
28
|
+
if require_in_project_and_no_droppr(1,"an app name","a name to create an app on appsendr",true)
|
29
|
+
name = args.join(" ").strip
|
30
|
+
resp = appsendr.create(name)
|
31
|
+
make_appsendr_dir if resp['message']
|
32
|
+
@app = [resp['message']['app']['id'],resp['message']['app']['name']]
|
33
|
+
write_app
|
34
|
+
display "Your app has been created."
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def link
|
40
|
+
if in_project_dir?
|
41
|
+
error "This app is already linked to an appsendr." unless !has_project_droppr?
|
42
|
+
|
43
|
+
app = list_apps_and_ask
|
44
|
+
return unless app
|
45
|
+
|
46
|
+
link = appsendr.link(app['id'])
|
47
|
+
make_appsendr_dir if link
|
48
|
+
@app = [app['id'],app['name']]
|
49
|
+
write_app
|
50
|
+
display "Your app has been linked."
|
51
|
+
|
52
|
+
else
|
53
|
+
error("You are not in a project")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def list_apps_and_ask
|
58
|
+
apps = []
|
59
|
+
lines = []
|
60
|
+
list = appsendr.list
|
61
|
+
if list["message"].size > 0
|
62
|
+
display "=== Your apps"
|
63
|
+
i = 0
|
64
|
+
list["message"].each{|app|
|
65
|
+
apps.push({"name"=>app['app']['name'], "id"=>app['app']['id']})
|
66
|
+
lines.push("#{i+=1}. #{app['app']['name'].ljust(35)}")
|
67
|
+
}
|
68
|
+
display lines.join("\n")
|
69
|
+
print "\n"
|
70
|
+
print "Enter the # for the app you wish to link to: "
|
71
|
+
app_number = ask
|
72
|
+
|
73
|
+
return apps[app_number.to_i-1]
|
74
|
+
|
75
|
+
else
|
76
|
+
display "You have no apps."
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# def info
|
81
|
+
# name = (args.first && !args.first =~ /^\-\-/) ? args.first : extract_app
|
82
|
+
# attrs = appsendr.info(name)
|
83
|
+
#
|
84
|
+
# attrs[:web_url] ||= "http://#{attrs[:name]}.#{heroku.host}/"
|
85
|
+
# attrs[:git_url] ||= "git@#{heroku.host}:#{attrs[:name]}.git"
|
86
|
+
#
|
87
|
+
# display "=== #{attrs[:name]}"
|
88
|
+
# display "Web URL: #{attrs[:web_url]}"
|
89
|
+
# display "Domain name: http://#{attrs[:domain_name]}/" if attrs[:domain_name]
|
90
|
+
# display "Git Repo: #{attrs[:git_url]}"
|
91
|
+
# display "Dynos: #{attrs[:dynos]}"
|
92
|
+
# display "Workers: #{attrs[:workers]}"
|
93
|
+
# display "Repo size: #{format_bytes(attrs[:repo_size])}" if attrs[:repo_size]
|
94
|
+
# display "Slug size: #{format_bytes(attrs[:slug_size])}" if attrs[:slug_size]
|
95
|
+
# display "Stack: #{attrs[:stack]}" if attrs[:stack]
|
96
|
+
# if attrs[:database_size]
|
97
|
+
# data = format_bytes(attrs[:database_size])
|
98
|
+
# if tables = attrs[:database_tables]
|
99
|
+
# data = data.gsub('(empty)', '0K') + " in #{quantify("table", tables)}"
|
100
|
+
# end
|
101
|
+
# display "Data size: #{data}"
|
102
|
+
# end
|
103
|
+
#
|
104
|
+
# if attrs[:cron_next_run]
|
105
|
+
# display "Next cron: #{format_date(attrs[:cron_next_run])} (scheduled)"
|
106
|
+
# end
|
107
|
+
# if attrs[:cron_finished_at]
|
108
|
+
# display "Last cron: #{format_date(attrs[:cron_finished_at])} (finished)"
|
109
|
+
# end
|
110
|
+
#
|
111
|
+
# unless attrs[:addons].empty?
|
112
|
+
# display "Addons: " + attrs[:addons].map { |a| a['description'] }.join(', ')
|
113
|
+
# end
|
114
|
+
#
|
115
|
+
# display "Owner: #{attrs[:owner]}"
|
116
|
+
# collaborators = attrs[:collaborators].delete_if { |c| c[:email] == attrs[:owner] }
|
117
|
+
# unless collaborators.empty?
|
118
|
+
# first = true
|
119
|
+
# lead = "Collaborators:"
|
120
|
+
# attrs[:collaborators].each do |collaborator|
|
121
|
+
# display "#{first ? lead : ' ' * lead.length} #{collaborator[:email]}"
|
122
|
+
# first = false
|
123
|
+
# end
|
124
|
+
# end
|
125
|
+
#
|
126
|
+
# if attrs[:create_status] != "complete"
|
127
|
+
# display "Create Status: #{attrs[:create_status]}"
|
128
|
+
# end
|
129
|
+
# end
|
130
|
+
|
131
|
+
protected
|
132
|
+
|
133
|
+
def make_appsendr_dir
|
134
|
+
if in_project_dir?
|
135
|
+
FileUtils.mkdir_p(Dir.pwd+"/"+AppSendr::PROJECT_DIR)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def get_app
|
140
|
+
return if @app
|
141
|
+
unless @app = read_app
|
142
|
+
end
|
143
|
+
@app
|
144
|
+
end
|
145
|
+
|
146
|
+
def get_app_id
|
147
|
+
return if @app_id
|
148
|
+
unless @app_id = read_app_id
|
149
|
+
end
|
150
|
+
@app_id
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
def write_app
|
155
|
+
FileUtils.mkdir_p(File.dirname(project_appsendr_app))
|
156
|
+
File.open(project_appsendr_app, 'w') do |f|
|
157
|
+
f.puts self.app.join("\n")
|
158
|
+
end
|
159
|
+
set_app_permissions
|
160
|
+
end
|
161
|
+
|
162
|
+
def set_app_permissions
|
163
|
+
FileUtils.chmod 0700, File.dirname(project_appsendr_app)
|
164
|
+
FileUtils.chmod 0600, project_appsendr_app
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
module AppSendr::Command
|
2
|
+
class Auth < Base
|
3
|
+
attr_accessor :credentials
|
4
|
+
|
5
|
+
def client
|
6
|
+
@client ||= init_for_credentials
|
7
|
+
end
|
8
|
+
|
9
|
+
def init_for_credentials
|
10
|
+
client = AppSendr::Client.new(api_key, host)
|
11
|
+
#client.on_warning { |msg| self.display("\n#{msg}\n\n") }
|
12
|
+
client
|
13
|
+
end
|
14
|
+
|
15
|
+
def auth_credentials(user,pass)
|
16
|
+
AppSendr::Client.auth(user,pass,host)
|
17
|
+
end
|
18
|
+
|
19
|
+
# just a stub; will raise if not authenticated
|
20
|
+
def check
|
21
|
+
client.list
|
22
|
+
end
|
23
|
+
|
24
|
+
def host
|
25
|
+
ENV['APPDROPPR_HOST'] || 'appsendr.com' ##'appsendr.heroku.com' #
|
26
|
+
end
|
27
|
+
|
28
|
+
def reauthorize
|
29
|
+
user_pass = ask_for_credentials
|
30
|
+
@credentials = auth_credentials(user_pass[0],user_pass[1])
|
31
|
+
write_credentials
|
32
|
+
end
|
33
|
+
|
34
|
+
def api_key
|
35
|
+
get_credentials
|
36
|
+
@credentials[0]
|
37
|
+
end
|
38
|
+
|
39
|
+
# def user # :nodoc:
|
40
|
+
# get_credentials
|
41
|
+
# @credentials[0]
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# def password # :nodoc:
|
45
|
+
# get_credentials
|
46
|
+
# @credentials[1]
|
47
|
+
# end
|
48
|
+
|
49
|
+
def get_credentials # :nodoc:
|
50
|
+
return if @credentials
|
51
|
+
unless @credentials = read_credentials
|
52
|
+
user_pass = ask_for_credentials
|
53
|
+
@credentials = auth_credentials(user_pass[0],user_pass[1])
|
54
|
+
|
55
|
+
#@credentials = ask_for_credentials
|
56
|
+
save_credentials
|
57
|
+
end
|
58
|
+
@credentials
|
59
|
+
end
|
60
|
+
|
61
|
+
def read_credentials
|
62
|
+
File.exists?(credentials_file) and File.read(credentials_file).split("\n")
|
63
|
+
end
|
64
|
+
|
65
|
+
def echo_off
|
66
|
+
system "stty -echo"
|
67
|
+
end
|
68
|
+
|
69
|
+
def echo_on
|
70
|
+
system "stty echo"
|
71
|
+
end
|
72
|
+
|
73
|
+
def ask_for_credentials
|
74
|
+
puts "Enter your AppSendr credentials."
|
75
|
+
|
76
|
+
print "Username: "
|
77
|
+
user = ask
|
78
|
+
|
79
|
+
print "Password: "
|
80
|
+
password = running_on_windows? ? ask_for_password_on_windows : ask_for_password
|
81
|
+
|
82
|
+
[ user, password ]
|
83
|
+
end
|
84
|
+
|
85
|
+
def ask_for_password_on_windows
|
86
|
+
require "Win32API"
|
87
|
+
char = nil
|
88
|
+
password = ''
|
89
|
+
|
90
|
+
while char = Win32API.new("crtdll", "_getch", [ ], "L").Call do
|
91
|
+
break if char == 10 || char == 13 # received carriage return or newline
|
92
|
+
if char == 127 || char == 8 # backspace and delete
|
93
|
+
password.slice!(-1, 1)
|
94
|
+
else
|
95
|
+
# windows might throw a -1 at us so make sure to handle RangeError
|
96
|
+
(password << char.chr) rescue RangeError
|
97
|
+
end
|
98
|
+
end
|
99
|
+
puts
|
100
|
+
return password
|
101
|
+
end
|
102
|
+
|
103
|
+
def ask_for_password
|
104
|
+
echo_off
|
105
|
+
password = ask
|
106
|
+
puts
|
107
|
+
echo_on
|
108
|
+
return password
|
109
|
+
end
|
110
|
+
|
111
|
+
def save_credentials
|
112
|
+
begin
|
113
|
+
write_credentials
|
114
|
+
#command = args.any? { |a| a == '--ignore-keys' } ? 'auth:check' : 'keys:add'
|
115
|
+
command = 'auth:check'
|
116
|
+
AppSendr::Command.run_internal(command, args)
|
117
|
+
rescue RestClient::Unauthorized => e
|
118
|
+
delete_credentials
|
119
|
+
raise e unless retry_login?
|
120
|
+
|
121
|
+
display "\nAuthentication failed"
|
122
|
+
user_pass = ask_for_credentials
|
123
|
+
@credentials = auth_credentials(user_pass[0],user_pass[1])
|
124
|
+
@client = init_for_credentials
|
125
|
+
retry
|
126
|
+
rescue Exception => e
|
127
|
+
delete_credentials
|
128
|
+
raise e
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def retry_login?
|
133
|
+
@login_attempts ||= 0
|
134
|
+
@login_attempts += 1
|
135
|
+
@login_attempts < 3
|
136
|
+
end
|
137
|
+
|
138
|
+
def write_credentials
|
139
|
+
FileUtils.mkdir_p(File.dirname(credentials_file))
|
140
|
+
File.open(credentials_file, 'w') do |f|
|
141
|
+
f.puts self.credentials
|
142
|
+
end
|
143
|
+
set_credentials_permissions
|
144
|
+
end
|
145
|
+
|
146
|
+
def set_credentials_permissions
|
147
|
+
FileUtils.chmod 0700, File.dirname(credentials_file)
|
148
|
+
FileUtils.chmod 0600, credentials_file
|
149
|
+
end
|
150
|
+
|
151
|
+
def delete_credentials
|
152
|
+
FileUtils.rm_f(credentials_file)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module AppSendr::Command
|
4
|
+
class Base
|
5
|
+
include AppSendr::Helpers
|
6
|
+
|
7
|
+
attr_accessor :args
|
8
|
+
attr_reader :autodetected_app
|
9
|
+
def initialize(args, appsendr=nil)
|
10
|
+
@args = args
|
11
|
+
@appsendr = appsendr
|
12
|
+
@autodetected_app = false
|
13
|
+
end
|
14
|
+
|
15
|
+
def confirm(message="Are you sure you wish to continue? (y/n)?")
|
16
|
+
display("#{message} ", false)
|
17
|
+
ask.downcase == 'y'
|
18
|
+
end
|
19
|
+
|
20
|
+
def format_date(date)
|
21
|
+
date = Time.parse(date) if date.is_a?(String)
|
22
|
+
date.strftime("%Y-%m-%d %H:%M %Z")
|
23
|
+
end
|
24
|
+
|
25
|
+
def ask
|
26
|
+
gets.strip
|
27
|
+
end
|
28
|
+
|
29
|
+
def appsendr
|
30
|
+
@appsendr ||= AppSendr::Command.run_internal('auth:client', args)
|
31
|
+
end
|
32
|
+
|
33
|
+
def extract_app(force=true)
|
34
|
+
app = extract_option('--app', false)
|
35
|
+
raise(CommandFailed, "You must specify an app name after --app") if app == false
|
36
|
+
unless app
|
37
|
+
app = extract_app_in_dir(Dir.pwd) ||
|
38
|
+
raise(CommandFailed, "No app specified.\nRun this command from app folder or set it adding --app <app name>") if force
|
39
|
+
@autodetected_app = true
|
40
|
+
end
|
41
|
+
app
|
42
|
+
end
|
43
|
+
|
44
|
+
def extract_option(options, default=true)
|
45
|
+
values = options.is_a?(Array) ? options : [options]
|
46
|
+
return unless opt_index = args.select { |a| values.include? a }.first
|
47
|
+
opt_position = args.index(opt_index) + 1
|
48
|
+
if args.size > opt_position && opt_value = args[opt_position]
|
49
|
+
if opt_value.include?('--')
|
50
|
+
opt_value = nil
|
51
|
+
else
|
52
|
+
args.delete_at(opt_position)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
opt_value ||= default
|
56
|
+
args.delete(opt_index)
|
57
|
+
block_given? ? yield(opt_value) : opt_value
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
end
|