social_snippet 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.gitignore +1 -0
- data/README.md +5 -5
- data/lib/social_snippet/api/completion_api.rb +13 -0
- data/lib/social_snippet/api/config_api.rb +14 -0
- data/lib/social_snippet/api/insert_snippet_api.rb +15 -0
- data/lib/social_snippet/api/install_repository_api.rb +109 -0
- data/lib/social_snippet/api/manifest_api.rb +83 -0
- data/lib/social_snippet/api/registry_api.rb +8 -0
- data/lib/social_snippet/api/search_api.rb +44 -0
- data/lib/social_snippet/api/show_api.rb +10 -0
- data/lib/social_snippet/api/update_repository_api.rb +54 -0
- data/lib/social_snippet/api.rb +20 -309
- data/lib/social_snippet/repository/repository_manager.rb +3 -1
- data/lib/social_snippet/resolvers/base_resolver.rb +21 -0
- data/lib/social_snippet/resolvers/dep_resolver.rb +7 -2
- data/lib/social_snippet/resolvers/insert_resolver.rb +8 -4
- data/lib/social_snippet/tag.rb +8 -0
- data/lib/social_snippet/tag_parser.rb +12 -22
- data/lib/social_snippet/version.rb +1 -1
- data/social_snippet.gemspec +2 -0
- data/spec/lib/command_line/sspm_init_spec.rb +1 -1
- data/spec/lib/insert_resolver_spec.rb +164 -109
- data/spec/lib/repository/repository_manager_spec.rb +8 -1
- data/test/base_resolver_test.rb +43 -0
- metadata +14 -3
data/lib/social_snippet/api.rb
CHANGED
@@ -1,4 +1,14 @@
|
|
1
|
-
|
1
|
+
class SocialSnippet::Api; end
|
2
|
+
|
3
|
+
require_relative "api/config_api"
|
4
|
+
require_relative "api/manifest_api"
|
5
|
+
require_relative "api/insert_snippet_api"
|
6
|
+
require_relative "api/install_repository_api"
|
7
|
+
require_relative "api/update_repository_api"
|
8
|
+
require_relative "api/completion_api"
|
9
|
+
require_relative "api/show_api"
|
10
|
+
require_relative "api/search_api"
|
11
|
+
require_relative "api/registry_api"
|
2
12
|
|
3
13
|
class SocialSnippet::Api
|
4
14
|
|
@@ -9,183 +19,15 @@ class SocialSnippet::Api
|
|
9
19
|
@social_snippet = new_social_snippet
|
10
20
|
end
|
11
21
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
22
|
-
|
23
|
-
# Initialize the snippet.json interactively.
|
24
|
-
# $ sspm init
|
25
|
-
def init_manifest(options = {})
|
26
|
-
answer = {}
|
27
|
-
json_str = "{}"
|
28
|
-
|
29
|
-
# load current configuration
|
30
|
-
if ::File.exists?("snippet.json")
|
31
|
-
answer = ::JSON.parse(::File.read "snippet.json")
|
32
|
-
end
|
33
|
-
|
34
|
-
loop do
|
35
|
-
answer = ask_manifest_questions(manifest_questions(answer), answer)
|
36
|
-
json_str = ::JSON.pretty_generate(answer)
|
37
|
-
social_snippet.logger.say ""
|
38
|
-
social_snippet.logger.say json_str
|
39
|
-
social_snippet.logger.say ""
|
40
|
-
break if ask_confirm("Is this okay? [Y/N]: ")
|
41
|
-
end
|
42
|
-
|
43
|
-
::File.write "snippet.json", json_str
|
44
|
-
|
45
|
-
answer
|
46
|
-
end
|
47
|
-
|
48
|
-
# Insert snippets to given text.
|
49
|
-
# $ ssnip
|
50
|
-
#
|
51
|
-
# @param src [String] The text of source code
|
52
|
-
#
|
53
|
-
def insert_snippet(src, options = {})
|
54
|
-
resolver = ::SocialSnippet::Resolvers::InsertResolver.new(social_snippet, options)
|
55
|
-
res = resolver.insert(src)
|
56
|
-
output res
|
57
|
-
res
|
58
|
-
end
|
59
|
-
|
60
|
-
# $ sspm install name
|
61
|
-
def install_repository_by_name(repo_name, repo_ref, options = {})
|
62
|
-
installed_as = repo_name
|
63
|
-
installed_as = options[:name] unless options[:name].nil?
|
64
|
-
|
65
|
-
unless installed_as === repo_name
|
66
|
-
output "Installing as #{installed_as}"
|
67
|
-
end
|
68
|
-
|
69
|
-
if social_snippet.repo_manager.exists?(installed_as, repo_ref)
|
70
|
-
output "#{installed_as} is already installed"
|
71
|
-
return
|
72
|
-
end
|
73
|
-
|
74
|
-
output "Finding: #{repo_name}"
|
75
|
-
info = social_snippet.registry_client.repositories.find(repo_name)
|
76
|
-
output "Found at: #{info["url"]}"
|
77
|
-
|
78
|
-
output "Cloning repository..."
|
79
|
-
repo = ::SocialSnippet::Repository::RepositoryFactory.clone(info["url"])
|
80
|
-
|
81
|
-
install_repository installed_as, repo_ref, repo
|
82
|
-
end
|
83
|
-
|
84
|
-
# $ sspm install URL
|
85
|
-
def install_repository_by_url(repo_url, repo_ref, options = {})
|
86
|
-
output "Cloning repository..."
|
87
|
-
repo = ::SocialSnippet::Repository::RepositoryFactory.clone(repo_url)
|
88
|
-
install_repository_by_repo repo, repo_ref, options
|
89
|
-
end
|
90
|
-
|
91
|
-
# $ sspm install ./path/to/repo
|
92
|
-
def install_repository_by_path(repo_path, repo_ref, options = {})
|
93
|
-
output "Cloning repository..."
|
94
|
-
repo = ::SocialSnippet::Repository::RepositoryFactory.clone_local(repo_path)
|
95
|
-
install_repository_by_repo repo, repo_ref, options
|
96
|
-
end
|
97
|
-
|
98
|
-
def install_repository_by_repo(repo, repo_ref, options)
|
99
|
-
installed_as = repo.name
|
100
|
-
installed_as = options[:name] unless options[:name].nil?
|
101
|
-
output "Installing as #{installed_as}"
|
102
|
-
|
103
|
-
if social_snippet.repo_manager.exists?(installed_as)
|
104
|
-
output "#{installed_as} is already installed"
|
105
|
-
return
|
106
|
-
end
|
107
|
-
|
108
|
-
install_repository installed_as, repo_ref, repo
|
109
|
-
end
|
110
|
-
|
111
|
-
# Update a repository
|
112
|
-
# $ sspm update repo-name
|
113
|
-
def update_repository(repo_name, options = {})
|
114
|
-
unless social_snippet.repo_manager.exists?(repo_name)
|
115
|
-
output "ERROR: #{repo_name} is not installed"
|
116
|
-
return
|
117
|
-
end
|
118
|
-
|
119
|
-
output "Fetching update for #{repo_name}"
|
120
|
-
ret = social_snippet.repo_manager.fetch(repo_name, options)
|
121
|
-
|
122
|
-
repo = social_snippet.repo_manager.find_repository(repo_name)
|
123
|
-
display_name = repo_name
|
124
|
-
|
125
|
-
# nothing to update
|
126
|
-
if ret == 0 && social_snippet.repo_manager.exists?(repo_name, repo.latest_version)
|
127
|
-
output "Everything up-to-date"
|
128
|
-
return
|
129
|
-
end
|
130
|
-
|
131
|
-
output "Updating #{repo_name}"
|
132
|
-
unless options[:dry_run]
|
133
|
-
version = repo.latest_version
|
134
|
-
if repo.has_versions? && repo.current_ref != version
|
135
|
-
output "Bumping version into #{version}"
|
136
|
-
display_name = "#{repo_name}\##{version}"
|
137
|
-
repo.checkout version
|
138
|
-
social_snippet.repo_manager.update repo_name, version, repo, options
|
139
|
-
end
|
140
|
-
social_snippet.repo_manager.cache_installing_repo repo
|
141
|
-
end
|
142
|
-
|
143
|
-
output "Success #{display_name}"
|
144
|
-
|
145
|
-
# update deps
|
146
|
-
if social_snippet.repo_manager.has_deps?(repo_name)
|
147
|
-
output "Updating #{display_name}'s dependencies"
|
148
|
-
deps = social_snippet.repo_manager.deps(repo_name)
|
149
|
-
install_missing_dependencies deps, options
|
150
|
-
output "Finish updating #{display_name}'s dependencies"
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
# Update all installed repositories
|
155
|
-
# $ sspm update
|
156
|
-
def update_all_repositories(options = {})
|
157
|
-
social_snippet.repo_manager.each_installed_repo do |repo_name|
|
158
|
-
update_repository repo_name, options
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
def complete_snippet_path(keyword)
|
163
|
-
social_snippet.repo_manager.complete(keyword)
|
164
|
-
end
|
165
|
-
|
166
|
-
def cli_complete_snippet_path(keyword)
|
167
|
-
complete_snippet_path(keyword).each do |cand_repo|
|
168
|
-
output cand_repo
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
def show_info(repo_name)
|
173
|
-
repo_info = social_snippet.registry_client.repositories.find(repo_name)
|
174
|
-
output ::JSON.pretty_generate(repo_info)
|
175
|
-
end
|
176
|
-
|
177
|
-
# $ sspm search query
|
178
|
-
def search_repositories(query, options = {})
|
179
|
-
format_text = search_result_format(options)
|
180
|
-
social_snippet.registry_client.repositories.search(query).each do |repo|
|
181
|
-
output format_text % search_result_list(repo, options)
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
def add_url(url, options = {})
|
186
|
-
ret = social_snippet.registry_client.repositories.add_url(url)
|
187
|
-
output ret
|
188
|
-
end
|
22
|
+
include ::SocialSnippet::Api::ConfigApi
|
23
|
+
include ::SocialSnippet::Api::ManifestApi
|
24
|
+
include ::SocialSnippet::Api::InsertSnippetApi
|
25
|
+
include ::SocialSnippet::Api::InstallRepositoryApi
|
26
|
+
include ::SocialSnippet::Api::UpdateRepositoryApi
|
27
|
+
include ::SocialSnippet::Api::CompletionApi
|
28
|
+
include ::SocialSnippet::Api::ShowApi
|
29
|
+
include ::SocialSnippet::Api::SearchApi
|
30
|
+
include ::SocialSnippet::Api::RegistryApi
|
189
31
|
|
190
32
|
#
|
191
33
|
# Helpers
|
@@ -193,137 +35,6 @@ class SocialSnippet::Api
|
|
193
35
|
|
194
36
|
private
|
195
37
|
|
196
|
-
# Install repository
|
197
|
-
#
|
198
|
-
# @param repo [::SocialSnippet::Repository::Drivers::BaseRepository]
|
199
|
-
def install_repository(repo_name, repo_ref, repo, options = {})
|
200
|
-
display_name = repo_name
|
201
|
-
|
202
|
-
if repo_ref.nil?
|
203
|
-
repo_ref = resolve_reference(repo)
|
204
|
-
|
205
|
-
if repo.has_versions?
|
206
|
-
output "Resolving #{display_name}'s version"
|
207
|
-
else
|
208
|
-
output "No versions, use current reference"
|
209
|
-
end
|
210
|
-
end
|
211
|
-
|
212
|
-
display_name = "#{repo_name}\##{repo_ref}"
|
213
|
-
|
214
|
-
output "Installing: #{display_name}"
|
215
|
-
unless options[:dry_run]
|
216
|
-
social_snippet.repo_manager.install repo_name, repo_ref, repo, options
|
217
|
-
end
|
218
|
-
|
219
|
-
output "Success: #{display_name}"
|
220
|
-
|
221
|
-
# install dependencies
|
222
|
-
if has_dependencies?(repo)
|
223
|
-
output "Finding #{display_name}'s dependencies"
|
224
|
-
install_missing_dependencies repo.dependencies, options
|
225
|
-
output "Finish finding #{display_name}'s dependencies"
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
def ask_confirm(message)
|
230
|
-
ret = social_snippet.prompt.ask(message) do |q|
|
231
|
-
q.limit = 1
|
232
|
-
q.validate = /^[yn]$/i
|
233
|
-
end
|
234
|
-
/y/i === ret
|
235
|
-
end
|
236
|
-
|
237
|
-
def ask_manifest_questions(questions, obj)
|
238
|
-
questions.inject(obj) do |obj, q|
|
239
|
-
obj[q[:key]] = ask_manifest_question(q)
|
240
|
-
obj
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
|
-
def ask_manifest_question(question)
|
245
|
-
if question[:type] === :string
|
246
|
-
social_snippet.prompt.ask("#{question[:key]}: ") do |q|
|
247
|
-
q.default = question[:default]
|
248
|
-
if question[:validate].is_a?(Regexp)
|
249
|
-
q.validate = question[:validate]
|
250
|
-
end
|
251
|
-
end
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
def manifest_questions(answer)
|
256
|
-
[
|
257
|
-
{
|
258
|
-
:key => "name",
|
259
|
-
:type => :string,
|
260
|
-
:validate => /[a-zA-Z0-9\.\-_]+/,
|
261
|
-
:default => answer["name"],
|
262
|
-
},
|
263
|
-
{
|
264
|
-
:key => "description",
|
265
|
-
:type => :string,
|
266
|
-
:default => answer["description"],
|
267
|
-
},
|
268
|
-
{
|
269
|
-
:key => "license",
|
270
|
-
:default => answer["license"] || "MIT",
|
271
|
-
:type => :string,
|
272
|
-
},
|
273
|
-
]
|
274
|
-
end
|
275
|
-
|
276
|
-
def resolve_reference(repo)
|
277
|
-
if repo.has_versions?
|
278
|
-
repo.latest_version
|
279
|
-
else
|
280
|
-
repo.current_ref
|
281
|
-
end
|
282
|
-
end
|
283
|
-
|
284
|
-
def has_dependencies?(repo)
|
285
|
-
repo.dependencies && ( not repo.dependencies.empty? )
|
286
|
-
end
|
287
|
-
|
288
|
-
def install_missing_dependencies(repo_deps, options = {})
|
289
|
-
repo_deps.each do |dep_repo_name, dep_repo_ref|
|
290
|
-
unless social_snippet.repo_manager.exists?(dep_repo_name, dep_repo_ref)
|
291
|
-
install_repository_by_name dep_repo_name, dep_repo_ref, options
|
292
|
-
end
|
293
|
-
end
|
294
|
-
end
|
295
|
-
|
296
|
-
def search_result_format(options)
|
297
|
-
keys = [ # TODO: improve (change order by option, etc...)
|
298
|
-
:name,
|
299
|
-
:desc,
|
300
|
-
:url,
|
301
|
-
:installed,
|
302
|
-
]
|
303
|
-
|
304
|
-
list = []
|
305
|
-
keys.each {|key| list.push "%s" if options[key] }
|
306
|
-
|
307
|
-
return list.join(" ")
|
308
|
-
end
|
309
|
-
|
310
|
-
def search_result_list(repo, options)
|
311
|
-
list = []
|
312
|
-
list.push repo["name"] if options[:name]
|
313
|
-
list.push "\"#{repo["desc"]}\"" if options[:desc]
|
314
|
-
list.push repo["url"] if options[:url]
|
315
|
-
list.push search_result_installed(repo) if options[:installed]
|
316
|
-
return list
|
317
|
-
end
|
318
|
-
|
319
|
-
def search_result_installed(repo)
|
320
|
-
if social_snippet.repo_manager.exists?(repo["name"])
|
321
|
-
"#installed"
|
322
|
-
else
|
323
|
-
""
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
327
38
|
def output(message)
|
328
39
|
social_snippet.logger.say message
|
329
40
|
end
|
@@ -77,6 +77,8 @@ module SocialSnippet::Repository
|
|
77
77
|
#
|
78
78
|
# @param name [String] The name of repository
|
79
79
|
def find_repository(name, ref = nil)
|
80
|
+
return nil if name.nil? || name.empty?
|
81
|
+
|
80
82
|
repo_paths.each do |repo_path|
|
81
83
|
path = "#{repo_path}/#{name}"
|
82
84
|
if ::Dir.exists?(path)
|
@@ -86,7 +88,7 @@ module SocialSnippet::Repository
|
|
86
88
|
end
|
87
89
|
end
|
88
90
|
|
89
|
-
|
91
|
+
nil
|
90
92
|
end
|
91
93
|
|
92
94
|
def find_repositories_start_with(prefix)
|
@@ -41,8 +41,29 @@ module SocialSnippet
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
+
# @param lines [Array<String>]
|
45
|
+
def filter(lines)
|
46
|
+
lines = cut_filter(lines)
|
47
|
+
lines
|
48
|
+
end
|
49
|
+
|
44
50
|
private
|
45
51
|
|
52
|
+
def cut_filter(lines)
|
53
|
+
cut_level = 0
|
54
|
+
lines.select do |line|
|
55
|
+
if Tag.is_begin_cut?(line)
|
56
|
+
cut_level += 1
|
57
|
+
false
|
58
|
+
elsif Tag.is_end_cut?(line)
|
59
|
+
cut_level -= 1
|
60
|
+
false
|
61
|
+
else
|
62
|
+
cut_level === 0
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
46
67
|
def move_context_by_tag!(context, tag)
|
47
68
|
if tag.has_repo?
|
48
69
|
if tag.has_ref?
|
@@ -48,8 +48,13 @@ module SocialSnippet
|
|
48
48
|
:tag => tag,
|
49
49
|
:context => new_context,
|
50
50
|
})
|
51
|
-
# find more deps
|
52
|
-
|
51
|
+
# find more deps
|
52
|
+
if snippet.is_a?(Snippet)
|
53
|
+
snippet_lines = snippet.lines
|
54
|
+
else
|
55
|
+
snippet_lines = snippet.split($/)
|
56
|
+
end
|
57
|
+
found_tags.push *find_func(snippet_lines, new_context, tag)
|
53
58
|
end
|
54
59
|
|
55
60
|
return found_tags
|
@@ -25,7 +25,7 @@ module SocialSnippet
|
|
25
25
|
# @param src [Array<String>] The text of source code
|
26
26
|
def insert(src)
|
27
27
|
context = Context.new("")
|
28
|
-
lines = src.split
|
28
|
+
lines = filter(src.split $/)
|
29
29
|
|
30
30
|
TagParser.find_snippet_tags(lines).each do |tag_info|
|
31
31
|
visit tag_info[:tag]
|
@@ -58,8 +58,12 @@ module SocialSnippet
|
|
58
58
|
end
|
59
59
|
|
60
60
|
# Insert snippet by tag and context
|
61
|
-
def insert_by_tag_and_context!(inserter,
|
62
|
-
|
61
|
+
def insert_by_tag_and_context!(inserter, snippet_str, context, tag)
|
62
|
+
if snippet_str.is_a?(Snippet)
|
63
|
+
src = insert_func(snippet_str.lines, context, tag)
|
64
|
+
else
|
65
|
+
src = insert_func(snippet_str.split($/), context, tag)
|
66
|
+
end
|
63
67
|
|
64
68
|
options[:margin_top].times { inserter.insert "" }
|
65
69
|
inserter.insert tag.to_snippet_tag # @snip -> @snippet
|
@@ -71,7 +75,7 @@ module SocialSnippet
|
|
71
75
|
|
72
76
|
# Insert depended snippet
|
73
77
|
def insert_depended_snippets!(inserter, snippet, context, tag)
|
74
|
-
dep_tags = deps_resolver.find(snippet.lines
|
78
|
+
dep_tags = deps_resolver.find(snippet.lines, context, tag)
|
75
79
|
dep_tags = sort_dep_tags_by_dep(dep_tags)
|
76
80
|
|
77
81
|
dep_tags.each do |tag_info|
|
data/lib/social_snippet/tag.rb
CHANGED
@@ -93,6 +93,14 @@ class SocialSnippet::Tag
|
|
93
93
|
|
94
94
|
class << self
|
95
95
|
|
96
|
+
def is_begin_cut?(s)
|
97
|
+
/@begin_cut/ === s
|
98
|
+
end
|
99
|
+
|
100
|
+
def is_end_cut?(s)
|
101
|
+
/@end_cut/ === s
|
102
|
+
end
|
103
|
+
|
96
104
|
# Check given line to match @snip tag
|
97
105
|
def is_snip_tag_line(s)
|
98
106
|
return /@snip\s*<.*?>/ === s
|
@@ -7,22 +7,7 @@ class SocialSnippet::TagParser
|
|
7
7
|
# @param s [String or Array] parsed text
|
8
8
|
# @return [Array] found `@snip` tags with line_no
|
9
9
|
def find_snip_tags(s)
|
10
|
-
|
11
|
-
|
12
|
-
lines = get_lines(s)
|
13
|
-
|
14
|
-
lines.each.with_index do |line, i|
|
15
|
-
if ::SocialSnippet::Tag.is_snip_tag_line(line)
|
16
|
-
found_lines.push(
|
17
|
-
{
|
18
|
-
:line_no => i,
|
19
|
-
:tag => ::SocialSnippet::Tag.new(line),
|
20
|
-
}
|
21
|
-
)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
return found_lines
|
10
|
+
find_lines(s) {|line| ::SocialSnippet::Tag.is_snip_tag_line(line) }
|
26
11
|
end
|
27
12
|
|
28
13
|
# Find `@snippet` tags from text
|
@@ -30,12 +15,14 @@ class SocialSnippet::TagParser
|
|
30
15
|
# @param s [String or Array] parsed text
|
31
16
|
# @return [Array] found `@snippet` tags with line_no
|
32
17
|
def find_snippet_tags(s)
|
33
|
-
|
18
|
+
find_lines(s) {|line| ::SocialSnippet::Tag.is_snippet_tag_line(line) }
|
19
|
+
end
|
34
20
|
|
35
|
-
|
21
|
+
private
|
36
22
|
|
37
|
-
|
38
|
-
|
23
|
+
def find_lines(s, &comparator)
|
24
|
+
get_lines(s).each.with_index.inject([]) do |found_lines, (line, i)|
|
25
|
+
if comparator.call(line)
|
39
26
|
found_lines.push(
|
40
27
|
{
|
41
28
|
:line_no => i,
|
@@ -43,9 +30,8 @@ class SocialSnippet::TagParser
|
|
43
30
|
}
|
44
31
|
)
|
45
32
|
end
|
33
|
+
found_lines
|
46
34
|
end
|
47
|
-
|
48
|
-
return found_lines
|
49
35
|
end
|
50
36
|
|
51
37
|
def get_lines(s)
|
@@ -53,6 +39,10 @@ class SocialSnippet::TagParser
|
|
53
39
|
s.split($/)
|
54
40
|
elsif s.is_a?(Array)
|
55
41
|
s
|
42
|
+
elsif s.is_a?(Enumerator)
|
43
|
+
s
|
44
|
+
else
|
45
|
+
raise "error unknown data"
|
56
46
|
end
|
57
47
|
end
|
58
48
|
|
data/social_snippet.gemspec
CHANGED
@@ -17,6 +17,8 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
18
|
spec.require_paths = ["lib"]
|
19
19
|
|
20
|
+
spec.required_ruby_version = ">= 1.9.3"
|
21
|
+
|
20
22
|
spec.add_runtime_dependency "version_sorter", "~> 1.1.0"
|
21
23
|
spec.add_runtime_dependency "rugged", ["~> 0.21.4", ">= 0.21.4"]
|
22
24
|
spec.add_runtime_dependency "rest-client", "~> 1.7.0"
|