turbogenerator 0.3.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/bin/turbo +19 -2
- data/lib/commander.rb +93 -0
- data/lib/hash_recursive.rb +18 -0
- data/lib/templates/command.erb +18 -0
- data/lib/templates/output.erb +8 -0
- data/lib/templates/resource-get.json +19 -5
- data/lib/turbo.rb +22 -68
- data/lib/value_object.rb +52 -0
- metadata +68 -16
- data/bin/before.sh, +0 -0
- data/lib/hash_recursive_merge.rb +0 -74
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
YjRmMzhkMTA0NGI3NTc1M2E5YTBmMGY0NzVmZjQ3MTFlY2MxNTUzYQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
YzZiMDk1ODFiZWJlZTBiNTI0ZmYyYzQwMmYxYmQyYWUzOThmNjQ1Yg==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NTlmZGVmNTNmMWM3Yjg4ZjU0NDU2ODFlMDQ4MjI5NTA5MDE5NTBiNWE1NGU0
|
10
|
+
NDk2MmZkNTRhNzFmZGQ1MTZiZDM5NDNjZjE0MjM1ODE0MTdmYWQ3MmEwMDk0
|
11
|
+
ZjA2OGNmYWE4YjBkMWY1NzI2ZjhkNjk3M2M1NzI5MjMwNzA1NWE=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZDM4OTMxZDM2NzUwNmVlZjUyODQ4OTc4OTc1Y2I5ZWE0ZWJjZTA5ZjIzNWM3
|
14
|
+
ZjQwYmNlYzBhZTZlYTcwZWExZTY2ODM0ZTRkNDUwOTFhNjczZmE0MjVjMDM1
|
15
|
+
NjUxZWI1ZWRmNjI2NTJjMjhkMmU5OTM4NWFiZDJjZGRlNzYzOTM=
|
data/bin/turbo
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require "thor"
|
4
|
+
require 'term/ansicolor'
|
4
5
|
require "turbo"
|
5
6
|
|
6
7
|
def get_real_path(path)
|
@@ -13,7 +14,7 @@ class TurboApp < Thor
|
|
13
14
|
def generate(name)
|
14
15
|
|
15
16
|
if File.exist? "workflows/#{name}"
|
16
|
-
puts "workflow #{name} has already exist under workflows/#{name}"
|
17
|
+
puts "workflow #{name.green} has already exist under workflows/#{name}"
|
17
18
|
return
|
18
19
|
end
|
19
20
|
|
@@ -32,7 +33,8 @@ class TurboApp < Thor
|
|
32
33
|
|
33
34
|
FileUtils.copy File.join(File.dirname(File.expand_path(__FILE__)), "../lib/templates/workflow.json"), "workflows/#{name}/workflow.json"
|
34
35
|
|
35
|
-
puts "
|
36
|
+
puts "Workflow `#{name.green}` is generated under workflows/#{name}"
|
37
|
+
puts "Run `turbo start #{name.green}` to start the workflow"
|
36
38
|
end
|
37
39
|
|
38
40
|
desc "start", "specify the workflow name"
|
@@ -40,9 +42,24 @@ class TurboApp < Thor
|
|
40
42
|
def start(workflow)
|
41
43
|
config = options[:config]
|
42
44
|
turbo = Turbo.new(config)
|
45
|
+
|
46
|
+
if(!File.exist?("workflows/#{workflow}/workflow.json"))
|
47
|
+
puts "Workflow `#{workflow.green}` does not exist"
|
48
|
+
puts "Run `turbo generate #{workflow.green}` to generate it first"
|
49
|
+
return
|
50
|
+
end
|
51
|
+
|
43
52
|
turbo.run_workflow(workflow)
|
44
53
|
end
|
45
54
|
|
55
|
+
desc "list", "list all workflows"
|
56
|
+
def list
|
57
|
+
if(File.exist?("workflows"))
|
58
|
+
system ('ls workflows/')
|
59
|
+
else
|
60
|
+
puts "No workflow found, you can generate one by using `turob generate my-workflow`"
|
61
|
+
end
|
62
|
+
end
|
46
63
|
end
|
47
64
|
|
48
65
|
TurboApp.start
|
data/lib/commander.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'json'
|
3
|
+
require 'hashugar'
|
4
|
+
require 'jsonpath'
|
5
|
+
|
6
|
+
require 'term/ansicolor'
|
7
|
+
|
8
|
+
require 'rexml/document'
|
9
|
+
include REXML
|
10
|
+
|
11
|
+
require 'value_object'
|
12
|
+
|
13
|
+
|
14
|
+
class String
|
15
|
+
include Term::ANSIColor
|
16
|
+
end
|
17
|
+
|
18
|
+
def verfiy_xpath(caze, result)
|
19
|
+
xmldoc = Document.new(result)
|
20
|
+
nodes = XPath.match(xmldoc, "#{caze.success.content}")
|
21
|
+
|
22
|
+
if nodes != nil
|
23
|
+
puts "Case: ['#{caze.name}'] passed".green
|
24
|
+
else
|
25
|
+
puts "Case: ['#{caze.name}'] failed\nExpected: #{caze.success.content}\nGot: #{result}".red
|
26
|
+
end
|
27
|
+
puts "#{caze.type} #{caze.url}\n".cyan
|
28
|
+
end
|
29
|
+
|
30
|
+
def verify_regexp(caze, result)
|
31
|
+
x = result.match(/#{caze.success.content}/)
|
32
|
+
|
33
|
+
if x != nil
|
34
|
+
puts "Case: ['#{caze.name}'] passed".green
|
35
|
+
else
|
36
|
+
puts "Case: ['#{caze.name}'] failed\nExpected: #{caze.success.content}\nGot: #{result}".red
|
37
|
+
end
|
38
|
+
puts "#{caze.type} #{caze.url}\n".cyan
|
39
|
+
end
|
40
|
+
|
41
|
+
def verify_jsonpath(caze, result)
|
42
|
+
nodes = JsonPath.on(result, "#{caze.success.content}")
|
43
|
+
|
44
|
+
if nodes.size != 0
|
45
|
+
puts "Case: ['#{caze.name}'] passed".green
|
46
|
+
else
|
47
|
+
puts "Case: ['#{caze.name}'] failed\nExpected: #{nodes}\nGot: #{result}".red
|
48
|
+
end
|
49
|
+
puts "#{caze.type} #{caze.url}\n".cyan
|
50
|
+
end
|
51
|
+
|
52
|
+
def verify(caze)
|
53
|
+
result = `#{caze.command}`
|
54
|
+
|
55
|
+
case caze.success.type
|
56
|
+
when 'xpath'
|
57
|
+
verfiy_xpath(caze, result)
|
58
|
+
when 'regexp'
|
59
|
+
verify_regexp(caze, result)
|
60
|
+
when 'jsonpath'
|
61
|
+
verify_jsonpath(caze, result)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def generate_command(config)
|
66
|
+
template = File.read(File.join(File.dirname(File.expand_path(__FILE__)), 'templates/command.erb'))
|
67
|
+
renderer = ERB.new(template)
|
68
|
+
|
69
|
+
puts "Scenario: #{config.name}, test cases: #{config.cases.size}\n".cyan
|
70
|
+
config.cases.each do |caze|
|
71
|
+
test_case = TestCase.new({
|
72
|
+
:name => caze.name,
|
73
|
+
:url => "#{config.baseurl}/#{caze.path}",
|
74
|
+
:headers => caze.headers,
|
75
|
+
:type => caze.type,
|
76
|
+
:data_path => caze.data,
|
77
|
+
:success => SuccessDefinition.new(caze.success),
|
78
|
+
:debug => caze.debug
|
79
|
+
})
|
80
|
+
|
81
|
+
command = renderer.result(test_case.get_binding).gsub("\n", " ").strip
|
82
|
+
|
83
|
+
test = ExecutableTest.new({
|
84
|
+
:name => caze.name,
|
85
|
+
:type => caze.type,
|
86
|
+
:url => "#{config.baseurl}/#{caze.path}",
|
87
|
+
:command => command,
|
88
|
+
:success => SuccessDefinition.new(caze.success)
|
89
|
+
})
|
90
|
+
|
91
|
+
verify(test)
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module HashRecursiveMerge
|
2
|
+
def rmerge!(other_hash)
|
3
|
+
merge!(other_hash) do |key, oldval, newval|
|
4
|
+
oldval.class == self.class ? oldval.rmerge!(newval) : newval
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
def rmerge(other_hash)
|
9
|
+
r = {}
|
10
|
+
merge(other_hash) do |key, oldval, newval|
|
11
|
+
r[key] = oldval.class == self.class ? oldval.rmerge(newval) : newval
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Hash
|
17
|
+
include HashRecursiveMerge
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
curl -s
|
2
|
+
<% if success.part == "header" %> -D - -o /dev/null<% end %>
|
3
|
+
|
4
|
+
-X <%= type %>
|
5
|
+
|
6
|
+
<% if ['POST', 'PUT'].include? type %>
|
7
|
+
--data @<%= data_path %>
|
8
|
+
<% end %>
|
9
|
+
|
10
|
+
<% headers.each_pair do |key, value| %>
|
11
|
+
--header <%= key %>=<%= value %>
|
12
|
+
<% end %>
|
13
|
+
|
14
|
+
<%= url %>
|
15
|
+
|
16
|
+
<% if debug %>
|
17
|
+
-D - -o debug.log
|
18
|
+
<% end %>
|
@@ -1,14 +1,28 @@
|
|
1
1
|
{
|
2
|
-
"
|
3
|
-
"
|
2
|
+
"name": "posts",
|
3
|
+
"baseurl": "http://localhost:8080",
|
4
4
|
"headers": {
|
5
5
|
"Accept": "application/json",
|
6
6
|
"Content-Type": "application/json"
|
7
7
|
},
|
8
8
|
"cases": [
|
9
|
-
{
|
10
|
-
"path": "/
|
11
|
-
"success":
|
9
|
+
{ "name": "list posts",
|
10
|
+
"path": "/api/feeds",
|
11
|
+
"success": {
|
12
|
+
"part": "body",
|
13
|
+
"type": "jsonpath",
|
14
|
+
"content": "$[0].url"
|
15
|
+
}
|
16
|
+
},
|
17
|
+
{ "name": "create posts",
|
18
|
+
"path": "/api/fav-feeds",
|
19
|
+
"type": "POST",
|
20
|
+
"data": "resource.json",
|
21
|
+
"success": {
|
22
|
+
"part": "header",
|
23
|
+
"type": "regexp",
|
24
|
+
"content": "200 OK"
|
25
|
+
}
|
12
26
|
}
|
13
27
|
]
|
14
28
|
}
|
data/lib/turbo.rb
CHANGED
@@ -2,31 +2,12 @@
|
|
2
2
|
|
3
3
|
require 'json'
|
4
4
|
require 'term/ansicolor'
|
5
|
+
require 'hashugar'
|
6
|
+
require 'rexml/document'
|
7
|
+
include REXML
|
5
8
|
|
6
|
-
|
7
|
-
|
8
|
-
# License:: MIT License
|
9
|
-
# Link:: http://www.simonecarletti.com/
|
10
|
-
# Source:: http://gist.github.com/gists/6391/
|
11
|
-
#
|
12
|
-
module HashRecursiveMerge
|
13
|
-
def rmerge!(other_hash)
|
14
|
-
merge!(other_hash) do |key, oldval, newval|
|
15
|
-
oldval.class == self.class ? oldval.rmerge!(newval) : newval
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def rmerge(other_hash)
|
20
|
-
r = {}
|
21
|
-
merge(other_hash) do |key, oldval, newval|
|
22
|
-
r[key] = oldval.class == self.class ? oldval.rmerge(newval) : newval
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
class Hash
|
28
|
-
include HashRecursiveMerge
|
29
|
-
end
|
9
|
+
require 'hash_recursive'
|
10
|
+
require 'commander'
|
30
11
|
|
31
12
|
class String
|
32
13
|
include Term::ANSIColor
|
@@ -46,23 +27,25 @@ class Turbo
|
|
46
27
|
@workflow_path = "workflows/#{workflow}"
|
47
28
|
@pre_command = "#{@workflow_path}/#{wf['before']}"
|
48
29
|
@post_command = "#{@workflow_path}/#{wf['after']}"
|
30
|
+
@debug_file = 'debug.log'
|
49
31
|
|
50
32
|
scenarios = wf['scenarios']
|
33
|
+
@run_success = 0
|
34
|
+
@run_failed = 0
|
51
35
|
|
52
|
-
|
36
|
+
execute_before_script
|
53
37
|
scenarios.each do |scenario|
|
54
38
|
run_scenario("#{@workflow_path}/scenarios/#{scenario}")
|
55
39
|
end
|
56
|
-
|
57
|
-
|
40
|
+
execute_after_script
|
58
41
|
end
|
59
42
|
|
60
43
|
private
|
61
|
-
def
|
44
|
+
def execute_before_script
|
62
45
|
system "#{@pre_command}"
|
63
46
|
end
|
64
47
|
|
65
|
-
def
|
48
|
+
def execute_after_script
|
66
49
|
system "#{@post_command}"
|
67
50
|
end
|
68
51
|
|
@@ -76,14 +59,6 @@ class Turbo
|
|
76
59
|
end
|
77
60
|
end
|
78
61
|
|
79
|
-
def generate_header(obj)
|
80
|
-
headers = []
|
81
|
-
obj.each_pair do |k, v|
|
82
|
-
headers << "-H \"#{k}: #{v}\""
|
83
|
-
end
|
84
|
-
headers.join(' ')
|
85
|
-
end
|
86
|
-
|
87
62
|
def load_common
|
88
63
|
JSON.parse(File.read(@conf['conf_path'] + '/' + @conf['common_conf']))
|
89
64
|
end
|
@@ -92,39 +67,18 @@ class Turbo
|
|
92
67
|
JSON.parse(File.read(scenario))
|
93
68
|
end
|
94
69
|
|
95
|
-
|
96
|
-
|
97
|
-
config = common.rmerge(load_scenario(scenario))
|
70
|
+
def bootstrap(scenario)
|
71
|
+
config = load_common.rmerge(load_scenario(scenario)).to_hashugar
|
98
72
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
end
|
103
|
-
|
104
|
-
# generate all headers
|
105
|
-
headers = generate_header(config['headers'])
|
106
|
-
|
107
|
-
# generate HTTP method
|
108
|
-
method = "-X #{config['method']}"
|
109
|
-
|
110
|
-
# run each case here
|
111
|
-
config['cases'].each do |caze|
|
112
|
-
path = config['baseurl'] + caze['path']
|
113
|
-
data = config['method'] == "POST" || config['method'] == "PUT" ? "-d @#{@workflow_path}/#{caze['data']}" : ""
|
114
|
-
|
115
|
-
debug = @conf['debug'] == 'true' || config['debug'] == 'true' ? "-D - -o debug.log" : ""
|
73
|
+
def config.get_binding
|
74
|
+
binding
|
75
|
+
end
|
116
76
|
|
117
|
-
|
118
|
-
|
119
|
-
command = "#{real_command} | grep --color=auto -E \"#{caze['success']}\""
|
77
|
+
config
|
78
|
+
end
|
120
79
|
|
121
|
-
|
80
|
+
def run_scenario(scenario)
|
81
|
+
generate_command(bootstrap(scenario))
|
82
|
+
end
|
122
83
|
|
123
|
-
if ret
|
124
|
-
puts "#{'Success'}: #{real_command}".green
|
125
|
-
else
|
126
|
-
puts "#{'Error'}: #{real_command}".red
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
84
|
end
|
data/lib/value_object.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
class TestCase
|
4
|
+
attr_accessor :name, :url, :headers, :type, :data_path, :debug, :success
|
5
|
+
|
6
|
+
def initialize(args)
|
7
|
+
obj = OpenStruct.new(args)
|
8
|
+
@name = obj.name
|
9
|
+
@url = obj.url
|
10
|
+
@headers = obj.headers || {}
|
11
|
+
@type = obj.type || "GET"
|
12
|
+
@data_path = obj.data_path
|
13
|
+
@success = obj.success
|
14
|
+
@debug = obj.debug
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_binding
|
18
|
+
binding
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class SuccessDefinition
|
23
|
+
attr_accessor :part, :type, :content
|
24
|
+
|
25
|
+
def initialize(args)
|
26
|
+
obj = OpenStruct.new(args)
|
27
|
+
@part = obj.part
|
28
|
+
@type = obj.type
|
29
|
+
@content = obj.content
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_binding
|
33
|
+
binding
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class ExecutableTest
|
38
|
+
attr_accessor :name, :type, :url, :command, :success
|
39
|
+
|
40
|
+
def initialize(args)
|
41
|
+
obj = OpenStruct.new(args)
|
42
|
+
@name = obj.name
|
43
|
+
@url = obj.url
|
44
|
+
@type = obj.type || "GET"
|
45
|
+
@command = obj.command
|
46
|
+
@success = obj.success
|
47
|
+
end
|
48
|
+
|
49
|
+
def get_binding
|
50
|
+
binding
|
51
|
+
end
|
52
|
+
end
|
metadata
CHANGED
@@ -1,91 +1,143 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: turbogenerator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.5.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Juntao Qiu
|
8
|
+
- Jia Wei
|
9
|
+
- Shen Tong
|
10
|
+
- Yan Yu
|
11
|
+
- Yang Mengmeng
|
9
12
|
autorequire:
|
10
13
|
bindir: bin
|
11
14
|
cert_chain: []
|
12
|
-
date:
|
15
|
+
date: 2015-03-12 00:00:00.000000000 Z
|
13
16
|
dependencies:
|
14
17
|
- !ruby/object:Gem::Dependency
|
15
18
|
name: thor
|
16
19
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
20
|
requirements:
|
21
|
+
- - ~>
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: '0.18'
|
19
24
|
- - ! '>='
|
20
25
|
- !ruby/object:Gem::Version
|
21
26
|
version: 0.18.1
|
22
27
|
type: :runtime
|
23
28
|
prerelease: false
|
24
29
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
30
|
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.18'
|
27
34
|
- - ! '>='
|
28
35
|
- !ruby/object:Gem::Version
|
29
36
|
version: 0.18.1
|
30
37
|
- !ruby/object:Gem::Dependency
|
31
38
|
name: term-ansicolor
|
32
39
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
40
|
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '1.3'
|
35
44
|
- - ! '>='
|
36
45
|
- !ruby/object:Gem::Version
|
37
46
|
version: 1.3.0
|
38
47
|
type: :runtime
|
39
48
|
prerelease: false
|
40
49
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
50
|
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.3'
|
43
54
|
- - ! '>='
|
44
55
|
- !ruby/object:Gem::Version
|
45
56
|
version: 1.3.0
|
46
|
-
|
47
|
-
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: hashugar
|
59
|
+
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ~>
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '1.0'
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 1.0.0
|
67
|
+
type: :runtime
|
68
|
+
prerelease: false
|
69
|
+
version_requirements: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ~>
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '1.0'
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 1.0.0
|
77
|
+
- !ruby/object:Gem::Dependency
|
78
|
+
name: jsonpath
|
79
|
+
requirement: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ~>
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0.5'
|
84
|
+
- - ! '>='
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: 0.5.7
|
87
|
+
type: :runtime
|
88
|
+
prerelease: false
|
89
|
+
version_requirements: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0.5'
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.5.7
|
97
|
+
description: Turbo is a HTTP API tester, it's a curl wrapper
|
48
98
|
email: juntao.qiu@gmail.com
|
49
99
|
executables:
|
50
100
|
- turbo
|
51
101
|
extensions: []
|
52
102
|
extra_rdoc_files: []
|
53
103
|
files:
|
54
|
-
- bin/before.sh,
|
55
104
|
- bin/turbo
|
105
|
+
- lib/commander.rb
|
56
106
|
- lib/config/browsers.json
|
57
107
|
- lib/config/common.json
|
58
108
|
- lib/config/turbo.conf
|
59
|
-
- lib/
|
109
|
+
- lib/hash_recursive.rb
|
60
110
|
- lib/templates/after.sh
|
61
111
|
- lib/templates/before.sh
|
112
|
+
- lib/templates/command.erb
|
113
|
+
- lib/templates/output.erb
|
62
114
|
- lib/templates/resource-get.json
|
63
115
|
- lib/templates/resource.json
|
64
116
|
- lib/templates/workflow.json
|
65
117
|
- lib/turbo.rb
|
118
|
+
- lib/value_object.rb
|
66
119
|
homepage: https://github.com/abruzzi/turbo
|
67
120
|
licenses:
|
68
121
|
- MIT
|
122
|
+
metadata: {}
|
69
123
|
post_install_message:
|
70
124
|
rdoc_options: []
|
71
125
|
require_paths:
|
72
126
|
- lib
|
73
127
|
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
-
none: false
|
75
128
|
requirements:
|
76
129
|
- - ! '>='
|
77
130
|
- !ruby/object:Gem::Version
|
78
131
|
version: '0'
|
79
132
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
-
none: false
|
81
133
|
requirements:
|
82
134
|
- - ! '>='
|
83
135
|
- !ruby/object:Gem::Version
|
84
136
|
version: '0'
|
85
137
|
requirements: []
|
86
138
|
rubyforge_project:
|
87
|
-
rubygems_version:
|
139
|
+
rubygems_version: 2.2.2
|
88
140
|
signing_key:
|
89
|
-
specification_version:
|
90
|
-
summary:
|
141
|
+
specification_version: 4
|
142
|
+
summary: Turbo is a HTTP API tester
|
91
143
|
test_files: []
|
data/bin/before.sh,
DELETED
File without changes
|
data/lib/hash_recursive_merge.rb
DELETED
@@ -1,74 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# = Hash Recursive Merge
|
3
|
-
#
|
4
|
-
# Merges a Ruby Hash recursively, Also known as deep merge.
|
5
|
-
# Recursive version of Hash#merge and Hash#merge!.
|
6
|
-
#
|
7
|
-
# Category:: Ruby
|
8
|
-
# Package:: Hash
|
9
|
-
# Author:: Simone Carletti <weppos@weppos.net>
|
10
|
-
# Copyright:: 2007-2008 The Authors
|
11
|
-
# License:: MIT License
|
12
|
-
# Link:: http://www.simonecarletti.com/
|
13
|
-
# Source:: http://gist.github.com/gists/6391/
|
14
|
-
#
|
15
|
-
module HashRecursiveMerge
|
16
|
-
|
17
|
-
#
|
18
|
-
# Recursive version of Hash#merge!
|
19
|
-
#
|
20
|
-
# Adds the contents of +other_hash+ to +hsh+,
|
21
|
-
# merging entries in +hsh+ with duplicate keys with those from +other_hash+.
|
22
|
-
#
|
23
|
-
# Compared with Hash#merge!, this method supports nested hashes.
|
24
|
-
# When both +hsh+ and +other_hash+ contains an entry with the same key,
|
25
|
-
# it merges and returns the values from both arrays.
|
26
|
-
#
|
27
|
-
# h1 = {"a" => 100, "b" => 200, "c" => {"c1" => 12, "c2" => 14}}
|
28
|
-
# h2 = {"b" => 254, "c" => 300, "c" => {"c1" => 16, "c3" => 94}}
|
29
|
-
# h1.rmerge!(h2) #=> {"a" => 100, "b" => 254, "c" => {"c1" => 16, "c2" => 14, "c3" => 94}}
|
30
|
-
#
|
31
|
-
# Simply using Hash#merge! would return
|
32
|
-
#
|
33
|
-
# h1.merge!(h2) #=> {"a" => 100, "b" = >254, "c" => {"c1" => 16, "c3" => 94}}
|
34
|
-
#
|
35
|
-
def rmerge!(other_hash)
|
36
|
-
merge!(other_hash) do |key, oldval, newval|
|
37
|
-
oldval.class == self.class ? oldval.rmerge!(newval) : newval
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
#
|
42
|
-
# Recursive version of Hash#merge
|
43
|
-
#
|
44
|
-
# Compared with Hash#merge!, this method supports nested hashes.
|
45
|
-
# When both +hsh+ and +other_hash+ contains an entry with the same key,
|
46
|
-
# it merges and returns the values from both arrays.
|
47
|
-
#
|
48
|
-
# Compared with Hash#merge, this method provides a different approch
|
49
|
-
# for merging nasted hashes.
|
50
|
-
# If the value of a given key is an Hash and both +other_hash+ abd +hsh
|
51
|
-
# includes the same key, the value is merged instead replaced with
|
52
|
-
# +other_hash+ value.
|
53
|
-
#
|
54
|
-
# h1 = {"a" => 100, "b" => 200, "c" => {"c1" => 12, "c2" => 14}}
|
55
|
-
# h2 = {"b" => 254, "c" => 300, "c" => {"c1" => 16, "c3" => 94}}
|
56
|
-
# h1.rmerge(h2) #=> {"a" => 100, "b" => 254, "c" => {"c1" => 16, "c2" => 14, "c3" => 94}}
|
57
|
-
#
|
58
|
-
# Simply using Hash#merge would return
|
59
|
-
#
|
60
|
-
# h1.merge(h2) #=> {"a" => 100, "b" = >254, "c" => {"c1" => 16, "c3" => 94}}
|
61
|
-
#
|
62
|
-
def rmerge(other_hash)
|
63
|
-
r = {}
|
64
|
-
merge(other_hash) do |key, oldval, newval|
|
65
|
-
r[key] = oldval.class == self.class ? oldval.rmerge(newval) : newval
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
end
|
70
|
-
|
71
|
-
|
72
|
-
class Hash
|
73
|
-
include HashRecursiveMerge
|
74
|
-
end
|