rhack 1.3.8 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rhack.rb +12 -4
- data/lib/rhack/clients.rb +1 -7
- data/lib/rhack/clients/base.rb +31 -11
- data/lib/rhack/clients/errors.rb +41 -0
- data/lib/rhack/dl.rb +1 -1
- data/lib/rhack/frame.rb +7 -1
- data/lib/rhack/js/johnson.rb +3 -3
- data/lib/rhack/page.rb +8 -8
- data/lib/rhack/scout.rb +20 -14
- data/lib/rhack/scout_squad.rb +3 -3
- data/lib/rhack/version.rb +1 -1
- metadata +11 -12
- data/lib/rhack/services.rb +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a6f9fd958d14ef221d1f20ebb4217decff1a257
|
4
|
+
data.tar.gz: 9b0d6cdf7cbe66b9d0f7ee3fa155761af34584c1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d7905168e4924ff769eb900fe57105edefa41ed98605b9421b4e9a4c1185e5ad3ce50c94034652cae9a94418f1b6fbc0da4058b153903bc91805224ba134e9ef
|
7
|
+
data.tar.gz: 2574c36ae2d5eabd0721d9134d38645963fcec1f49495642084bf63a24d1bc116cfc508564bc3c11b8e78ef212a0bc9870d9e5de30e7b7962e487136358c9339
|
data/lib/rhack.rb
CHANGED
@@ -50,7 +50,7 @@ module RHACK
|
|
50
50
|
if uas = uas.desktop.to_s and File.file? uas
|
51
51
|
@@useragents = IO.read(uas)/"\n"
|
52
52
|
else
|
53
|
-
@@useragents = ['Mozilla/5.0 (
|
53
|
+
@@useragents = ['Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.89 Safari/537.36']
|
54
54
|
end
|
55
55
|
|
56
56
|
class Scout
|
@@ -58,9 +58,9 @@ module RHACK
|
|
58
58
|
mattr_accessor :retry, :timeout
|
59
59
|
|
60
60
|
scout = RHACK.config.scout || {}
|
61
|
-
@@retry = scout.retry.
|
62
|
-
@@timeout = scout.timeout.
|
63
|
-
@@cacert = scout.cacert.
|
61
|
+
@@retry = scout.retry.presence || {}
|
62
|
+
@@timeout = scout.timeout.presence || 60
|
63
|
+
@@cacert = scout.cacert.presence ? File.expand_path(scout.cacert) : File.expand_path('../../config/cacert.pem', __FILE__)
|
64
64
|
end
|
65
65
|
|
66
66
|
end
|
@@ -89,5 +89,13 @@ require "rhack/scout_squad"
|
|
89
89
|
require "rhack/frame"
|
90
90
|
require "rhack/page"
|
91
91
|
if defined? Redis::Objects
|
92
|
+
# redis storage for namespaced cache, oauth data etc
|
92
93
|
require "rhack/storage"
|
93
94
|
end
|
95
|
+
|
96
|
+
module RHACK
|
97
|
+
# key feature
|
98
|
+
autoload :Client, 'rhack/clients'
|
99
|
+
# basic client for oauth
|
100
|
+
autoload :OAuthClient, 'rhack/clients/oauth'
|
101
|
+
end
|
data/lib/rhack/clients.rb
CHANGED
@@ -1,10 +1,4 @@
|
|
1
1
|
require 'rhack'
|
2
2
|
require 'rhack/clients/base'
|
3
3
|
require 'rhack/clients/storage'
|
4
|
-
require 'rhack/clients/
|
5
|
-
|
6
|
-
module RHACK
|
7
|
-
for name in [:Service, :ServiceError]
|
8
|
-
autoload name, 'rhack/clients/compatibility'
|
9
|
-
end
|
10
|
-
end
|
4
|
+
require 'rhack/clients/errors'
|
data/lib/rhack/clients/base.rb
CHANGED
@@ -1,29 +1,42 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
|
3
|
-
# TODO 1.0+: опция для клиента, чтобы это описание имело смысл, т.к. сейчас это ложь:
|
4
|
-
# Вызовам клиентов всегда следует ждут и возвращают обработанный ответ, если вызвваны без блока.
|
5
|
-
# В противном случае используется событийная модель и обработанный ответ передаётся в блок.
|
6
2
|
module RHACK
|
7
3
|
|
8
4
|
class Client
|
9
5
|
attr_reader :service
|
10
6
|
attr_accessor :f
|
11
7
|
class_attribute :frame_defaults, :instance_writer => false
|
8
|
+
class_attribute :scouts_initializers, :instance_writer => false
|
12
9
|
class_attribute :accounts, :instance_writer => false
|
13
10
|
class_attribute :routes, :instance_writer => false
|
14
11
|
class_attribute :rootpath, :instance_writer => false
|
15
12
|
|
16
13
|
self.frame_defaults = {}
|
14
|
+
self.scouts_initializers = []
|
17
15
|
self.accounts = {}
|
18
16
|
self.routes = {}
|
19
17
|
|
20
18
|
class << self
|
21
19
|
|
22
20
|
def inherited(child)
|
23
|
-
child.class_eval
|
21
|
+
child.class_eval do
|
24
22
|
include RHACK
|
25
23
|
__init__
|
26
|
-
|
24
|
+
|
25
|
+
# Proxying Rails router methods digging into the client namespace
|
26
|
+
if defined? ::Rails.application.routes.url_helpers
|
27
|
+
url_helpers = ::Rails.application.routes.url_helpers
|
28
|
+
routes_namespace = name.gsub(/::/, '').underscore.sub(/_client$/, '')
|
29
|
+
route_pattern = /^(.+_)?#{routes_namespace}_(.+)/
|
30
|
+
url_helpers.my_methods.each {|name|
|
31
|
+
if name.to_s[route_pattern]
|
32
|
+
full_route_name = $&
|
33
|
+
define_method "#$1#$2" do |*options|
|
34
|
+
url_helpers.send full_route_name, *options
|
35
|
+
end
|
36
|
+
end
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
27
40
|
end
|
28
41
|
|
29
42
|
def method_missing(method, *args, &block)
|
@@ -55,8 +68,11 @@ module RHACK
|
|
55
68
|
end
|
56
69
|
|
57
70
|
# Set default Frame options
|
58
|
-
def frame(dict)
|
71
|
+
def frame(dict, &scout_initializer)
|
59
72
|
self.frame_defaults += dict
|
73
|
+
if scout_initializer
|
74
|
+
self.scouts_initializers << scout_initializer
|
75
|
+
end
|
60
76
|
end
|
61
77
|
|
62
78
|
# Set usable accounts
|
@@ -78,6 +94,13 @@ module RHACK
|
|
78
94
|
if self.class.const_defined? :Result
|
79
95
|
opts[:result] = self.class::Result
|
80
96
|
end
|
97
|
+
if scouts_initializers = self.scouts_initializers.presence
|
98
|
+
opts[:on_scout_initialize] ||= lambda {|scout|
|
99
|
+
scouts_initializers.each {|initializer|
|
100
|
+
initializer.call scout
|
101
|
+
}
|
102
|
+
}
|
103
|
+
end
|
81
104
|
@f = Frame(rootpath || route(service) || route(:login), opts)
|
82
105
|
end
|
83
106
|
end
|
@@ -120,7 +143,7 @@ module RHACK
|
|
120
143
|
def route(name, interpolation=nil)
|
121
144
|
if url = routes[name]
|
122
145
|
if interpolation
|
123
|
-
url %= interpolation
|
146
|
+
url %= interpolation.symbolize_keys
|
124
147
|
end
|
125
148
|
if url !~ /^\w+:/
|
126
149
|
url = File.join rootpath, url
|
@@ -129,8 +152,6 @@ module RHACK
|
|
129
152
|
end
|
130
153
|
end
|
131
154
|
alias :url :route
|
132
|
-
# URI is deprecated # backward compatibility
|
133
|
-
alias :URI :route
|
134
155
|
|
135
156
|
def account(name)
|
136
157
|
accounts[name]
|
@@ -138,5 +159,4 @@ module RHACK
|
|
138
159
|
|
139
160
|
end
|
140
161
|
|
141
|
-
class ClientError < Exception; end
|
142
162
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module RHACK
|
2
|
+
|
3
|
+
# Abstraction, don't use it.
|
4
|
+
class BasicError < StandardError
|
5
|
+
# keep here debugful data
|
6
|
+
attr_accessor :details
|
7
|
+
|
8
|
+
# # Usage ...
|
9
|
+
# # ... without :details keyword, as usual:
|
10
|
+
# raise ServerError, 'an error has occured'
|
11
|
+
# # ... with :details keyword
|
12
|
+
# raise ServerError.new 'an error has occured', details: @curl_res
|
13
|
+
# # ... if you also want to set custom backtrace
|
14
|
+
# raise ServerError.new('an error has occured', details: @curl_res), backtrace_array
|
15
|
+
def initialize(message, *opts) # details: nil
|
16
|
+
@details = opts.extract_options![:details]
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
# The client couldn't connect and yet we don't know whose this fault is,
|
23
|
+
# e.g. domain lookup error or timeout.
|
24
|
+
class ConnectionError < BasicError; end
|
25
|
+
|
26
|
+
# The client successfully connected to the server
|
27
|
+
# but it returned an improper, non-descriptive response,
|
28
|
+
# e.g. 500 status, empty body, etc.
|
29
|
+
class ServerError < BasicError; end
|
30
|
+
|
31
|
+
# The client successfully connected to the server
|
32
|
+
# but server didn't accept a request and returned a descriptive exception,
|
33
|
+
# e.g. 406 status, body with only "error" key, etc.
|
34
|
+
class RequestError < BasicError; end
|
35
|
+
|
36
|
+
# The client successfully connected to the server,
|
37
|
+
# the server accept a request but we failed to process a response,
|
38
|
+
# e.g. because of an unexpected response structure
|
39
|
+
class ClientError < BasicError; end
|
40
|
+
|
41
|
+
end
|
data/lib/rhack/dl.rb
CHANGED
data/lib/rhack/frame.rb
CHANGED
@@ -25,6 +25,8 @@ module RHACK
|
|
25
25
|
alias options opts
|
26
26
|
@@cache = {}
|
27
27
|
|
28
|
+
# Opts passed to Scout:
|
29
|
+
# :ck / :cp, :raise, :timeout, :retry, :redir
|
28
30
|
def initialize *args
|
29
31
|
#args << 10 unless args[-1].is Fixnum
|
30
32
|
#args.insert -2, {} unless args[-2].is Hash
|
@@ -44,6 +46,10 @@ module RHACK
|
|
44
46
|
@static = false
|
45
47
|
end
|
46
48
|
@ss = ScoutSquad @loc.href, @opts, scouts_count
|
49
|
+
# for low-level settings that are not implemented explicitly
|
50
|
+
if @opts[:on_scout_initialize].present?
|
51
|
+
each &@opts[:on_scout_initialize]
|
52
|
+
end
|
47
53
|
end
|
48
54
|
|
49
55
|
def update_loc url
|
@@ -256,7 +262,7 @@ module RHACK
|
|
256
262
|
order = [del ? :loadDelete : :loadGet, url]
|
257
263
|
end
|
258
264
|
end
|
259
|
-
if
|
265
|
+
if order.blank? and orders.blank?
|
260
266
|
raise ArgumentError, "failed to run blank request#{'s' if many}, params was
|
261
267
|
(#{args.inspect[1..-2]})"
|
262
268
|
end
|
data/lib/rhack/js/johnson.rb
CHANGED
@@ -20,7 +20,7 @@ module Johnson
|
|
20
20
|
class << self
|
21
21
|
|
22
22
|
def runtime_set?(opts)
|
23
|
-
|
23
|
+
opts[:eval].blank? or (@@browser and @@browser.thread_id == Curl.carier_thread.object_id)
|
24
24
|
end
|
25
25
|
|
26
26
|
# CarierThread breaks if Multi has no work && CarierThread
|
@@ -36,9 +36,9 @@ module Johnson
|
|
36
36
|
unless runtime_set? opts
|
37
37
|
if Curl.status
|
38
38
|
Curl.recall
|
39
|
-
|
39
|
+
L.debug 'recalled'
|
40
40
|
end
|
41
|
-
if opts[:thread_safe].
|
41
|
+
if opts[:thread_safe].present?
|
42
42
|
@@browser = new_browser(opts[:jq])
|
43
43
|
L.debug "#@@browser initialized in #{Thread.current}\nmain: #{Thread.main}; carier: #{Curl.carier_thread}"
|
44
44
|
else
|
data/lib/rhack/page.rb
CHANGED
@@ -49,7 +49,7 @@ module RHACK
|
|
49
49
|
if obj.is Curl::Easy or obj.kinda Scout
|
50
50
|
c = obj.kinda(Scout) ? obj.http : obj
|
51
51
|
# just (c, loc) would pass to #process opts variable that returns '' on any key
|
52
|
-
process(c, loc.
|
52
|
+
process(c, loc.presence || {})
|
53
53
|
else
|
54
54
|
@body = obj
|
55
55
|
@loc = loc
|
@@ -57,7 +57,7 @@ module RHACK
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def empty?
|
60
|
-
!@data &&
|
60
|
+
!@data && @body.blank?
|
61
61
|
end
|
62
62
|
|
63
63
|
def size
|
@@ -215,10 +215,10 @@ module RHACK
|
|
215
215
|
document.domain = location.host;"
|
216
216
|
find("script").each {|n|
|
217
217
|
L.debug n.text.strip
|
218
|
-
if text = n.text.strip.
|
218
|
+
if text = n.text.strip.presence
|
219
219
|
js[:write_output] = ''
|
220
220
|
eval_string text
|
221
|
-
if res = js[:write_output].
|
221
|
+
if res = js[:write_output].presence then n.after res end
|
222
222
|
n.remove!
|
223
223
|
elsif frame and n.src
|
224
224
|
eval_string frame.get_cached expand_link n.src
|
@@ -251,10 +251,10 @@ module RHACK
|
|
251
251
|
end
|
252
252
|
|
253
253
|
def title(full=true)
|
254
|
-
if @data.nil? and !@failed and @body.
|
254
|
+
if @data.nil? and !@failed and @body.present?
|
255
255
|
if full
|
256
256
|
to_html unless defined? @doc
|
257
|
-
if @doc.title.
|
257
|
+
if @doc.title.present?
|
258
258
|
@title = @doc.title
|
259
259
|
else
|
260
260
|
@title = @loc.href
|
@@ -454,7 +454,7 @@ module RHACK
|
|
454
454
|
if form_node['method'].downcase == 'post'
|
455
455
|
[hash, form_node.enctype =~ /multipart/, action, opts]
|
456
456
|
else
|
457
|
-
action = "#{action}#{action['?'] ? '&' : '?'}#{hash.urlencode}" if hash.
|
457
|
+
action = "#{action}#{action['?'] ? '&' : '?'}#{hash.urlencode}" if hash.present?
|
458
458
|
[action, opts]
|
459
459
|
end
|
460
460
|
end
|
@@ -496,7 +496,7 @@ module RHACK
|
|
496
496
|
|
497
497
|
def get_links(links='a')
|
498
498
|
begin
|
499
|
-
links = find(links).map {|e| e.href}.
|
499
|
+
links = find(links).map {|e| e.href}.presence || find(links+'//a').map {|e| e.href} if links.is String
|
500
500
|
rescue LibXML::XML::Error
|
501
501
|
links = [links]
|
502
502
|
end
|
data/lib/rhack/scout.rb
CHANGED
@@ -193,7 +193,7 @@ module RHACK
|
|
193
193
|
when Curl::Response
|
194
194
|
ck = res['cookies']
|
195
195
|
end
|
196
|
-
return if
|
196
|
+
return if ck.blank?
|
197
197
|
ck.each {|c| Cookie(c, self)}
|
198
198
|
end
|
199
199
|
|
@@ -253,12 +253,15 @@ module RHACK
|
|
253
253
|
retry!
|
254
254
|
else
|
255
255
|
L.debug "#{curl_err} -> not reloading scout"
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
256
|
+
begin
|
257
|
+
raise @error if @raise_err
|
258
|
+
#raise *@error if @raise_err # old
|
259
|
+
yield if block_given?
|
260
|
+
ensure
|
261
|
+
# Now, we assume that data of this @http have been copied or will not be used anymore,
|
262
|
+
# thus the scout can be reused.
|
263
|
+
@busy = false
|
264
|
+
end
|
262
265
|
end
|
263
266
|
end
|
264
267
|
|
@@ -302,14 +305,17 @@ module RHACK
|
|
302
305
|
process_cookies res if @cookies_enabled
|
303
306
|
# We cannot just cancel on_complete in on_redirect block,
|
304
307
|
# because loadGet should (and will) immediately reset on_complete back.
|
305
|
-
if res.code.in(300..399) and
|
308
|
+
if res.code.in(300..399) and not_redir.blank? and (relvl -= 1) > -1 and loc = res.hash.location
|
306
309
|
loadGet(loc, headers: headers, relvl: relvl, redir: true, &callback)
|
307
310
|
else
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
311
|
+
begin
|
312
|
+
yield @http if block_given?
|
313
|
+
ensure
|
314
|
+
# Now, we assume that data of this @http have been copied or will not be used anymore,
|
315
|
+
# thus the scout can be reused.
|
316
|
+
@busy = false
|
317
|
+
@http.on_failure &Proc::NULL
|
318
|
+
end
|
313
319
|
end
|
314
320
|
}
|
315
321
|
# Curl::Err::* (TCP/IP level) exception callback.
|
@@ -353,7 +359,7 @@ module RHACK
|
|
353
359
|
unless hash.is Hash # not parameterized
|
354
360
|
opts[:headers] = opts[:headers].reverse_merge 'Content-Type' => 'application/octet-stream'
|
355
361
|
end
|
356
|
-
mkBody hash, multipart.
|
362
|
+
mkBody hash, multipart.present?
|
357
363
|
@last_method = :post
|
358
364
|
if block_given?
|
359
365
|
@post_proc = callback
|
data/lib/rhack/scout_squad.rb
CHANGED
@@ -62,7 +62,7 @@ module RHACK
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def rand
|
65
|
-
raise PickError if
|
65
|
+
raise PickError if empty?
|
66
66
|
# to_a because Array#reject returns object of this class
|
67
67
|
if scout = to_a.rand_by_available?
|
68
68
|
L.debug {"randomly picked an available scout##{scout.object_id}"}
|
@@ -74,7 +74,7 @@ module RHACK
|
|
74
74
|
end
|
75
75
|
|
76
76
|
def next
|
77
|
-
raise PickError if
|
77
|
+
raise PickError if empty?
|
78
78
|
if scout = to_a.find_available?
|
79
79
|
L.debug {"picked the next available scout##{scout.object_id}"}
|
80
80
|
scout
|
@@ -86,7 +86,7 @@ module RHACK
|
|
86
86
|
|
87
87
|
def to_s
|
88
88
|
str = '<#ScoutSquad @ '
|
89
|
-
if
|
89
|
+
if any?
|
90
90
|
if first.webproxy
|
91
91
|
str << "#{first.proxy} ~ "
|
92
92
|
elsif first.proxy
|
data/lib/rhack/version.rb
CHANGED
metadata
CHANGED
@@ -1,41 +1,41 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rhack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sergey Baev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-08-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rmtools
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '2.4'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '2.4'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: libxml-ruby
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '2.7'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '2.7'
|
41
41
|
description: 'RHACK is Ruby Http ACcess Kit: curl-based web-client framework created
|
@@ -49,7 +49,7 @@ extensions:
|
|
49
49
|
- ext/curb/extconf.rb
|
50
50
|
extra_rdoc_files: []
|
51
51
|
files:
|
52
|
-
- .gitignore
|
52
|
+
- ".gitignore"
|
53
53
|
- CURB-LICENSE
|
54
54
|
- Gemfile
|
55
55
|
- LICENSE
|
@@ -91,6 +91,7 @@ files:
|
|
91
91
|
- lib/rhack/clients.rb
|
92
92
|
- lib/rhack/clients/base.rb
|
93
93
|
- lib/rhack/clients/compatibility.rb
|
94
|
+
- lib/rhack/clients/errors.rb
|
94
95
|
- lib/rhack/clients/examples.rb
|
95
96
|
- lib/rhack/clients/oauth.rb
|
96
97
|
- lib/rhack/clients/storage.rb
|
@@ -116,7 +117,6 @@ files:
|
|
116
117
|
- lib/rhack/proxy/list.rb
|
117
118
|
- lib/rhack/scout.rb
|
118
119
|
- lib/rhack/scout_squad.rb
|
119
|
-
- lib/rhack/services.rb
|
120
120
|
- lib/rhack/storage.rb
|
121
121
|
- lib/rhack/version.rb
|
122
122
|
- lib/rhack_in.rb
|
@@ -134,19 +134,18 @@ require_paths:
|
|
134
134
|
- lib
|
135
135
|
required_ruby_version: !ruby/object:Gem::Requirement
|
136
136
|
requirements:
|
137
|
-
- -
|
137
|
+
- - ">="
|
138
138
|
- !ruby/object:Gem::Version
|
139
139
|
version: '0'
|
140
140
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
141
141
|
requirements:
|
142
|
-
- -
|
142
|
+
- - ">="
|
143
143
|
- !ruby/object:Gem::Version
|
144
144
|
version: '0'
|
145
145
|
requirements: []
|
146
146
|
rubyforge_project:
|
147
|
-
rubygems_version: 2.
|
147
|
+
rubygems_version: 2.2.2
|
148
148
|
signing_key:
|
149
149
|
specification_version: 4
|
150
150
|
summary: Curl-based web-client framework created for developing web-scrapers/bots
|
151
151
|
test_files: []
|
152
|
-
has_rdoc:
|
data/lib/rhack/services.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'rhack/clients'
|