steam-trade 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +33 -4
- data/lib/Badge.rb +133 -0
- data/lib/Confirmation.rb +4 -6
- data/lib/Guard.rb +4 -2
- data/lib/Inventory.rb +111 -0
- data/lib/LoginExecutor.rb +15 -6
- data/lib/Misc.rb +37 -1
- data/lib/Playerinfo.rb +28 -0
- data/lib/Trade.rb +82 -24
- data/lib/blueprints/appid_title.json +1 -0
- data/lib/blueprints/byappid.json +1 -0
- data/lib/meta/version.rb +4 -0
- data/lib/steam-trade.rb +50 -11
- data/steam-trade.gemspec +6 -5
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 34bdbd304683a4b23f616f4b8ebfb86f05c6a5f5
|
4
|
+
data.tar.gz: 0af0c76c9407399eaec724220221219bba88382b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c44ba8afd2b5441d8b52b039ef7260473e11a6a23116021073dbd6c260132c8bfe0b856efce97ccc1446bb874c30666c9acd04df9ddba804c7c27b0b790d082f
|
7
|
+
data.tar.gz: f8f65ea446d9a23a221aad67baa992ea0d5805df846ad1ff5920eb972128d7f094d54650637290ad82b6937b2fbf352e70f36494a0534b506ebeeb2a1ba7cb8d
|
data/README.md
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# steam-trade
|
2
2
|
|
3
|
-
This gem simplifes/allows sending steam trade offers programmatically
|
3
|
+
This gem simplifes/allows sending steam trade offers programmatically.
|
4
4
|
|
5
|
+
this gem is primarly for trading cards, tho can be used to CS:GO and other games inventories
|
5
6
|
## Installation
|
6
7
|
in your commandline :
|
7
8
|
|
@@ -12,7 +13,7 @@ First you need to require the gem:
|
|
12
13
|
```ruby
|
13
14
|
require 'steam-trade'
|
14
15
|
```
|
15
|
-
|
16
|
+
## Logging-in
|
16
17
|
then you need to login and optionally set your shared_secret and identity_secret:
|
17
18
|
- `shared_secret` is used to generate steam authentication codes so you won't have to write them manually each time you login.
|
18
19
|
- `identity_secret` is used to confirm trade offers automatically.
|
@@ -24,14 +25,42 @@ account = Handler.new('username','password','shared_secret') # share secret is o
|
|
24
25
|
|
25
26
|
|
26
27
|
account.mobile_info('identity_secret')
|
27
|
-
#identity_secret is
|
28
|
+
#identity_secret is required
|
28
29
|
|
29
30
|
```
|
31
|
+
## Getting someone's inventory
|
32
|
+
#### `normal_get_inventory('steamid','inventoryappid','contextid')`
|
33
|
+
- `steamid` is the target's steamid
|
34
|
+
- `inventoryappid` is the inventory type you want to load, ex : normal inventory(the one which holds trading cards), it's is 753
|
35
|
+
- `contextid` required to make a correct request to steam servers, ex:for normal inventory(the one which holds trading cards), it's is 6
|
36
|
+
- if you call `normal_get_inventory()` with no params, it will be default use the current logged-in account `steamid`, `inventoryappid = 753` and `contextid = 6`
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
require 'steam-trade'
|
40
|
+
|
41
|
+
account = Handler.new('username','password','shared_secret')
|
42
|
+
account.mobile_info('identity_secret')
|
43
|
+
|
44
|
+
my_inventory = normal_get_inventory() #if you are logged in you can call this command with no parameters to get the logged account's inventory
|
45
|
+
|
46
|
+
partner_inventory = normal_get_inventory('76561198044170935')
|
47
|
+
```
|
48
|
+
the returned items from `normal_get_inventory()` are in the form of an array example : `[item1,item2,item3...itemN]`.
|
49
|
+
|
50
|
+
each item is a hash which contains information about the item in the form of `{"appid"=>'xxx',"contextid"=>'xxx',"assetid" => 'xxx',"classid"=> 'xxx',......"name"=> 'xxxx',"market_fee_app" => 'xxx',....}`.
|
51
|
+
|
52
|
+
`market_fee_app` key gives you the appid of the game's app ( for trading cards), for other items technically `inventoryappid` is the games appid.
|
53
|
+
|
54
|
+
`name` key gives you the item name.
|
55
|
+
####
|
30
56
|
|
31
|
-
|
57
|
+
**IMPORTANT**: `normal_get_inventory()` will load the whole target inventory, for each **5k** of items, you are adding **~40MB** to your memory and of course will affect performance of the code and the computer
|
58
|
+
## Sending a trade offer
|
59
|
+
then you can send your offer
|
32
60
|
- `Myarray` is an array which contains hashes of selected items to send in the offer. (currently you must get this alone)
|
33
61
|
- `Theirarray` is an array which contains hashes of selected items to receive in the offer. (currently you must get this alone)
|
34
62
|
- `trade_offer_link` is the trade link of you partner `ex: https://steamcommunity.com/tradeoffer/new/?partner=410155236&token=H-yK-GFt`
|
63
|
+
- `trade_offer_link` can also be a steamID, however using a steamID requires you and your partner to be friends on steam
|
35
64
|
- `message` is the comment you want to include in the trade offer
|
36
65
|
|
37
66
|
- `Myarray`, `Theirarray`, `trade_offer_link` are required, `message` is optional
|
data/lib/Badge.rb
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
module BadgeCommands
|
2
|
+
|
3
|
+
def sets_count(steamid = @steamid, use_nonmarketable = true)
|
4
|
+
|
5
|
+
|
6
|
+
if steamid == nil
|
7
|
+
output "no steamid specified"
|
8
|
+
return
|
9
|
+
end
|
10
|
+
|
11
|
+
thread = Thread.new(steamid) { |steamid| ##getting name
|
12
|
+
targetname = ''
|
13
|
+
begin
|
14
|
+
data = get_player_summaries(steamid)
|
15
|
+
data.each { |acc|
|
16
|
+
if id["steamid"].to_s == steamid.to_s
|
17
|
+
targetname = id["personaname"]
|
18
|
+
end
|
19
|
+
}
|
20
|
+
rescue
|
21
|
+
targetname = ''
|
22
|
+
end
|
23
|
+
}
|
24
|
+
|
25
|
+
items = normal_get_inventory(steamid)
|
26
|
+
sorted = {}
|
27
|
+
items.each { |asset|
|
28
|
+
if use_nonmarketable == false
|
29
|
+
if asset["marketable"] == 0 || asset["tags"][-1]["localized_tag_name"] != "Trading Card" || asset["tags"][-2]["localized_tag_name"] == "Foil"
|
30
|
+
next
|
31
|
+
end
|
32
|
+
else
|
33
|
+
if asset["tags"][-1]["localized_tag_name"] != "Trading Card" || asset["tags"][-2]["localized_tag_name"] == "Foil"
|
34
|
+
next
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
name = asset["name"].sub(" (Trading Card)", "")
|
39
|
+
appid = asset["market_fee_app"].to_s
|
40
|
+
if sorted.has_key?(appid) == true
|
41
|
+
if sorted[appid].has_key?(name) == true
|
42
|
+
sorted[appid][name] = sorted[appid][name] + 1
|
43
|
+
elsif sorted[appid].has_key?(name) == false
|
44
|
+
sorted[appid][name] = 1
|
45
|
+
end
|
46
|
+
elsif sorted.has_key?(appid) == false
|
47
|
+
sorted[appid] = {}
|
48
|
+
sorted[appid][name] = 1
|
49
|
+
end
|
50
|
+
}
|
51
|
+
|
52
|
+
bigdata = JSON.parse(File.read("#{@libdir}/blueprints/byappid.json",:external_encoding => 'utf-8',:internal_encoding => 'utf-8'))
|
53
|
+
counted = {}
|
54
|
+
|
55
|
+
sorted.each { |appid,cards|
|
56
|
+
|
57
|
+
|
58
|
+
counted[appid] = bigdata[appid].merge(cards)
|
59
|
+
}
|
60
|
+
|
61
|
+
setsowned = {}
|
62
|
+
numberofsets = 0
|
63
|
+
total_non_foil = 0
|
64
|
+
|
65
|
+
counted.each { |appid,cards|
|
66
|
+
lowest = 9999
|
67
|
+
cards.each { |cardname, amount|
|
68
|
+
if amount < lowest then lowest = amount end
|
69
|
+
total_non_foil = total_non_foil + amount
|
70
|
+
}
|
71
|
+
setsowned[appid] = lowest
|
72
|
+
numberofsets = numberofsets + lowest
|
73
|
+
}
|
74
|
+
|
75
|
+
persona = thread.value
|
76
|
+
write_badges(counted,setsowned,numberofsets,total_non_foil, use_nonmarketable,persona,steamid)
|
77
|
+
if use_nonmarketable == false
|
78
|
+
return {'sets' => counted, 'appxsets' => setsowned, 'totalsets' => numberofsets, 'totalcards' => total_non_foil, 'marketable' => false}
|
79
|
+
else
|
80
|
+
return {'sets' => counted, 'appxsets' => setsowned, 'totalsets' => numberofsets, 'totalcards' => total_non_foil, 'marketable' => true}
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
private
|
86
|
+
def write_badges(hashofcards,eachappidsets,totalsets,total_non_foil,use_nonmarketable,persona,steamid)
|
87
|
+
if persona == ''
|
88
|
+
filename = steamid
|
89
|
+
else
|
90
|
+
filename = persona
|
91
|
+
end
|
92
|
+
|
93
|
+
"./#{filename}_badges.txt"
|
94
|
+
titles = JSON.parse(File.read("#{@libdir}/blueprints/appid_title.json",:external_encoding => 'utf-8',:internal_encoding => 'utf-8'))
|
95
|
+
eachappidsets = eachappidsets.sort_by do |k,v|
|
96
|
+
v
|
97
|
+
end
|
98
|
+
eachappidsets.reverse!
|
99
|
+
begin
|
100
|
+
File.truncate("./#{filename}_badges.txt", 0)
|
101
|
+
rescue
|
102
|
+
end
|
103
|
+
|
104
|
+
File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts "for #{persona}(#{steamid})"}
|
105
|
+
if use_nonmarketable == false
|
106
|
+
File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts "total non-foil trading cards #{total_non_foil}"}
|
107
|
+
File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts "only marketable cards are counted"}
|
108
|
+
else
|
109
|
+
File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts "total non-foil trading cards #{total_non_foil}"}
|
110
|
+
File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts "all cards counted including non-marketable"}
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts "total sets in target account #{totalsets}"}
|
115
|
+
File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts ""}
|
116
|
+
File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts ""}
|
117
|
+
|
118
|
+
|
119
|
+
eachappidsets.each { |appid, sets|
|
120
|
+
File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts "#{titles[appid]}, sets = #{sets}, appid = #{appid}"}
|
121
|
+
hashofcards[appid].each { |cardname, owned|
|
122
|
+
File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts "#{cardname} xxx #{owned}"}
|
123
|
+
}
|
124
|
+
File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts ""}
|
125
|
+
File.open("./#{filename}_badges.txt",'a+:UTF-8') {|f| f.puts ""}
|
126
|
+
}
|
127
|
+
|
128
|
+
output "badges.txt has been created"
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
|
133
|
+
end
|
data/lib/Confirmation.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
|
1
|
+
|
2
2
|
|
3
3
|
|
4
4
|
module ConfirmationCommands
|
5
|
-
|
5
|
+
|
6
6
|
|
7
7
|
|
8
8
|
|
@@ -54,8 +54,7 @@ module ConfirmationCommands
|
|
54
54
|
response = @session.get('https://steamcommunity.com/mobileconf/conf', params, no, headers)
|
55
55
|
html = response.content
|
56
56
|
if html.include?('Steam Guard Mobile Authenticator is providing incorrect Steam Guard codes.')
|
57
|
-
|
58
|
-
exit
|
57
|
+
raise("identity secret: #{@identity_secret} is incorrect")
|
59
58
|
end
|
60
59
|
return html
|
61
60
|
end
|
@@ -71,8 +70,7 @@ module ConfirmationCommands
|
|
71
70
|
return confirmhash
|
72
71
|
end
|
73
72
|
}
|
74
|
-
|
75
|
-
exit
|
73
|
+
raise("Could not find the offer to confirm")
|
76
74
|
end
|
77
75
|
|
78
76
|
def fetch_confirmation_details_page(hash) ##eigth
|
data/lib/Guard.rb
CHANGED
@@ -4,13 +4,14 @@ module GuardCommands
|
|
4
4
|
|
5
5
|
|
6
6
|
|
7
|
-
def fa()
|
7
|
+
def fa(shared_secret = @secret)
|
8
|
+
raise "No shared_secret given" if shared_secret == nil # cause upon initialization @secret = nil
|
8
9
|
timestamp = Time.new.to_i
|
9
10
|
math = timestamp / 30
|
10
11
|
math = math.to_i
|
11
12
|
time_buffer =[math].pack('Q>')
|
12
13
|
|
13
|
-
hmac = OpenSSL::HMAC.digest('sha1', Base64.decode64(
|
14
|
+
hmac = OpenSSL::HMAC.digest('sha1', Base64.decode64(shared_secret), time_buffer)
|
14
15
|
|
15
16
|
start = hmac[19].ord & 0xf
|
16
17
|
last = start + 4
|
@@ -29,6 +30,7 @@ module GuardCommands
|
|
29
30
|
|
30
31
|
end
|
31
32
|
|
33
|
+
private
|
32
34
|
def generate_confirmation_key(tag_string, time_stamp)
|
33
35
|
buffer = [time_stamp].pack('Q>') + tag_string.encode('ascii')
|
34
36
|
return Base64.encode64(OpenSSL::HMAC.digest('sha1', Base64.decode64(@identity_secret), buffer))
|
data/lib/Inventory.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
module InventoryCommands
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
def normal_get_inventory(steamid = @steamid ,appid = 753,context = 6)
|
8
|
+
if steamid == nil
|
9
|
+
output "no steamid specified"
|
10
|
+
return
|
11
|
+
elsif steamid.to_i == 0 && steamid.include?("?partner=") ##supplied trade link
|
12
|
+
partner_raw = steamid.split('partner=',2)[1].split('&',2)[0]
|
13
|
+
steamid = partner_id_to_steam_id(partner_raw)
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
if @inventory_cache == true
|
18
|
+
verdict = verify_inventory_cache(steamid)
|
19
|
+
if verdict != false
|
20
|
+
return verdict
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
items = []
|
26
|
+
last_id = 0
|
27
|
+
until last_id == false
|
28
|
+
received = get_inventory_chunk_normal_way(appid,context,steamid,last_id)
|
29
|
+
last_id = received['new_last_id']
|
30
|
+
items = items + received['assets']
|
31
|
+
output "loaded #{items.length}"
|
32
|
+
sleep(2) if last_id != false
|
33
|
+
end
|
34
|
+
|
35
|
+
output "total loaded #{items.length} asset"
|
36
|
+
if @inventory_cache == true
|
37
|
+
File.open("./#{steamid}.inventory", 'w') {|f| f.puts items.to_json}
|
38
|
+
end
|
39
|
+
|
40
|
+
return items
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
def get_inventory_chunk_normal_way(appid,context,steamid,last_id)
|
45
|
+
|
46
|
+
|
47
|
+
html = open("https://steamcommunity.com/inventory/#{steamid}/#{appid}/#{context}?start_assetid=#{last_id}&count=5000").read
|
48
|
+
|
49
|
+
get = JSON.parse(html)
|
50
|
+
|
51
|
+
if get.keys[3].to_s == "last_assetid"
|
52
|
+
|
53
|
+
new_last_id = get.values[3].to_s
|
54
|
+
|
55
|
+
else
|
56
|
+
new_last_id = false
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
assets = get["assets"]
|
61
|
+
descriptions = get["descriptions"]
|
62
|
+
|
63
|
+
|
64
|
+
descriptions_classids = {} ###sorting descriptions by key value || key is classid of the item's description
|
65
|
+
descriptions.each {|description|
|
66
|
+
classidxinstance = description["classid"] + '_' + description["instanceid"] # some items has the same classid but different instane id
|
67
|
+
descriptions_classids[classidxinstance] = description
|
68
|
+
}
|
69
|
+
|
70
|
+
assets.each { |asset| ## merging assets with names
|
71
|
+
classidxinstane = asset["classid"] + '_' + asset["instanceid"]
|
72
|
+
asset.replace(asset.merge(descriptions_classids[classidxinstance]))
|
73
|
+
}
|
74
|
+
|
75
|
+
|
76
|
+
return {'assets' => assets, 'new_last_id' =>new_last_id}
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
|
82
|
+
|
83
|
+
|
84
|
+
def verify_inventory_cache(steamid)
|
85
|
+
if File.exists?("./#{steamid}.inventory") == false
|
86
|
+
return false
|
87
|
+
end
|
88
|
+
puts File.mtime("./#{steamid}.inventory").to_s
|
89
|
+
puts Time.now.to_s
|
90
|
+
file_last_time = Time.parse(File.mtime("./#{steamid}.inventory").to_s)
|
91
|
+
current_time = Time.parse(Time.now.to_s)
|
92
|
+
calcule = current_time - file_last_time
|
93
|
+
puts "difference #{calcule}"
|
94
|
+
if calcule.to_i > @inventory_validity
|
95
|
+
File.delete("./#{steamid}.inventory")
|
96
|
+
return false
|
97
|
+
else
|
98
|
+
output "gonna use cached inventory which is #{calcule} seconds old"
|
99
|
+
begin
|
100
|
+
return JSON.parse(File.read("./#{steamid}.inventory",:external_encoding => 'utf-8',:internal_encoding => 'utf-8'))
|
101
|
+
rescue
|
102
|
+
File.delete("./#{steamid}.inventory")
|
103
|
+
return false
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
|
111
|
+
end
|
data/lib/LoginExecutor.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module LoginCommands
|
2
2
|
|
3
3
|
########################################################################################
|
4
|
-
def login
|
4
|
+
def login()
|
5
5
|
data = pass_stamp()
|
6
6
|
encrypted_password = data["password"]
|
7
7
|
timestamp = data["timestamp"]
|
@@ -30,13 +30,11 @@ module LoginCommands
|
|
30
30
|
|
31
31
|
login = @session.post('https://store.steampowered.com/login/dologin', send )
|
32
32
|
response = JSON::parse(login.body)
|
33
|
-
|
33
|
+
output "logging-in"
|
34
34
|
if response["success"] == true
|
35
35
|
repeater = true
|
36
36
|
elsif repeater == 3
|
37
|
-
|
38
|
-
puts "exiting"
|
39
|
-
exit
|
37
|
+
raise "Login failed username: #{@username}, password: #{@password} tried 3 times"
|
40
38
|
else
|
41
39
|
puts "re-trying to login"
|
42
40
|
puts "sleeping for 6 seconds"
|
@@ -71,7 +69,18 @@ module LoginCommands
|
|
71
69
|
|
72
70
|
cookie = Mechanize::Cookie.new :domain => 'steamcommunity.com', :name =>'sessionid', :value =>steampowered_sessionid, :path => '/'
|
73
71
|
@session.cookie_jar << cookie
|
74
|
-
|
72
|
+
@loggedin = true
|
73
|
+
@api_key = Nokogiri::HTML(@session.get("https://steamcommunity.com/dev/apikey").content).css('#bodyContents_ex').css('p').first.text.sub('Key: ','')
|
74
|
+
|
75
|
+
data = get_player_summaries(@steamid)
|
76
|
+
data.each { |element|
|
77
|
+
if element["steamid"].to_s == @steamid.to_s
|
78
|
+
@persona = element["personaname"]
|
79
|
+
end
|
80
|
+
}
|
81
|
+
output "logged in as #{@persona}"
|
82
|
+
output "your steamid is #{@steamid}"
|
83
|
+
output "loaded API_KEY : #{@api_key}"
|
75
84
|
end
|
76
85
|
########################################################################################
|
77
86
|
|
data/lib/Misc.rb
CHANGED
@@ -1,5 +1,17 @@
|
|
1
|
-
|
1
|
+
|
2
|
+
module MiscCommands
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
|
2
8
|
########################################################################################
|
9
|
+
def set_steamid(steamid)
|
10
|
+
@steamid = steamid
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
|
3
15
|
def copy_session
|
4
16
|
return @session
|
5
17
|
end
|
@@ -37,6 +49,10 @@ module Abilites
|
|
37
49
|
|
38
50
|
|
39
51
|
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
|
40
56
|
private
|
41
57
|
def partner_id_to_steam_id(account_id)
|
42
58
|
unknown_constant = 17825793 # or 0x1100001 idk wtf is this but ....
|
@@ -45,6 +61,26 @@ module Abilites
|
|
45
61
|
collect = last_bytes + first_bytes
|
46
62
|
return collect.unpack('Q>')[0].to_s
|
47
63
|
end
|
64
|
+
def output(message)
|
65
|
+
time = Time.new
|
66
|
+
add = time.strftime("%d-%m-%Y %H:%M:%S")
|
67
|
+
puts "#{time} :: #{message}"
|
68
|
+
end
|
69
|
+
|
48
70
|
|
49
71
|
|
50
72
|
end
|
73
|
+
|
74
|
+
module Util
|
75
|
+
def self.gem_libdir
|
76
|
+
require_relative 'meta/version.rb'
|
77
|
+
gem_name = 'steam-trade'
|
78
|
+
version = '0.0.5'
|
79
|
+
t = ["#{File.dirname(File.expand_path($0))}/#{Meta::GEM_NAME}.rb",
|
80
|
+
"#{Gem.dir}/gems/#{Meta::GEM_NAME}-#{Meta::VERSION}/lib/#{Meta::GEM_NAME}.rb"]
|
81
|
+
t.each {|i|
|
82
|
+
return i.gsub("#{Meta::GEM_NAME}.rb", '') if File.readable?(i)
|
83
|
+
}
|
84
|
+
raise "both paths are invalid: #{t}, while getting gemlib directory"
|
85
|
+
end
|
86
|
+
end
|