better_rest 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5ae32fec3199b120a02f3aeb8516fbf0b20bf0f0
4
- data.tar.gz: e6f83ccfc53e4bab8352d8ca475d9dc796d43fd8
3
+ metadata.gz: c7075c76283c5d80eaf7a1b277a64378a6564b08
4
+ data.tar.gz: a2565755ea3043e17f2d703a910ce1cc132fc2a6
5
5
  SHA512:
6
- metadata.gz: 724c77c7b7aa06c20e936ad58b93153f3f11d6e1719c8984ced94147c9f3b06bccd821c7b12771c7a2330db7df28aa7b2cd39bf8a2d9dc95b018596f5b1688f5
7
- data.tar.gz: 1b1c5192205df953ea1c67f4bc949d03f752ee5a42b21839fd77c257812f95f45ca0e283d826fdd1506d06a4d989a0309e76fec4c958db4330f33dafefb2f0bb
6
+ metadata.gz: fa1d80f4cee1b2043d862f06e279ac13bbb95bc946292f5312cc9ba317230836d0d5feacd1eb9ad7e7cb21adebe7aced9434fcfd26b9c7751fe91bb430664e43
7
+ data.tar.gz: c8e0e912bd2b05e9cc5c5ba86d6fb6b28042c25fa29923bbab877a7b8d01c4f0632e69a3c6c143f910ad2f1d5b2280a28dc6b6bb4b52f490d407f54ecd6d6c2e
data/README.md CHANGED
@@ -1,31 +1,36 @@
1
1
  # BetteR
2
2
 
3
- BetteR is a a REST testing client written in Ruby and served by Sinatra.
3
+ BetteR is a a REST testing client written in Ruby and served by Sinatra.
4
4
 
5
- BetteR emphasises both a clean and easy to use interface, as well as allowing users to have a very granuler control over their requests (things like following redirects, verbosity of response, timeout intervals are all configurable). The current feature set is modest, but what it does, it aims to do well.
5
+ BetteR emphasises both a clean and easy to use interface, as well as allowing users to have a very granuler control over their requests (things like following redirects, verbosity of response and timeout intervals are all configurable). The current feature set is modest, but what it does, it aims to do well.
6
6
 
7
- ## Usage
8
-
9
- The easiest way to use BetteR is to install it using the gem:
7
+ ## Screenshot
10
8
 
11
- $gem install better_rest
9
+ ![Screenshot](http://at1as.github.io/github_repo_assets/BetteR-reqeust.jpg)
12
10
 
13
- Or download the reposity here and launch BetteR via
11
+ ## Usage
14
12
 
15
- $./bin/better_rest
16
-
13
+ The easiest way to use BetteR is to install it using the gem:
14
+ ```bash
15
+ $ gem install better_rest
16
+ ```
17
+ Or download the repository here for the latest version and launch BetteR via:
18
+ ```bash
19
+ $ ./bin/better_rest
20
+ ```
17
21
  ## Logs
18
22
 
19
23
  Logs (if enabled from the Settings menu in the UI) will be stored in the following location
20
-
21
- ./logs/YYYY-MM-DD.log
22
-
24
+ ```bash
25
+ ./logs/YYYY-MM-DD.log
26
+ ```
23
27
  ## Dependencies
24
28
 
25
- Requires a ruby installation with the following Gems (installation via the gem should take care of these dependencies):
26
- - 'sinatra' (sudo gem install sinatra)
27
- - 'typhoeus' (sudo gem install typhoeus)
28
- - 'vegas' (sudo gem install vegas)
29
+ Requires a ruby installation with the following gems installed (installation via the gem will eventually take care of these dependencies, but currently does not):
30
+ - sinatra
31
+ - typhoeus
32
+ - vegas
33
+ - json
29
34
 
30
35
  ## TODO
31
36
 
@@ -33,4 +38,4 @@ Requires a ruby installation with the following Gems (installation via the gem s
33
38
  * Update current deprecated Basic/Digest Auth method
34
39
  * Add ability to save requests
35
40
  * Add download to file
36
- * Add parallel requests
41
+ * Add support for more than one variable
data/better_rest.gemspec CHANGED
@@ -1,15 +1,12 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "better_rest"
3
- s.version = "0.1.0"
4
- s.add_runtime_dependency "sinatra", '~> 1.4', ">= 1.4.4"
5
- s.add_runtime_dependency "vegas", '~> 0.1', ">= 0.1.11"
6
- s.add_runtime_dependency "typhoeus", '~> 0.6', '>= 0.6.7'
7
- s.licenses = ['MIT']
3
+ s.version = "0.1.1"
4
+ s.licenses = ['MIT']
8
5
  s.summary = "REST test Client"
9
- s.date = "2014-05-01"
10
- s.description = "A REST testing client delivered via Sinatra to any web browser."
6
+ s.date = "2014-08-29"
7
+ s.description = "This is a REST API test client accessible via the browser."
11
8
  s.authors = ["Jason Willems"]
12
- s.email = ["hello@jasonwillems.com"]
9
+ s.email = ["jason@willems.ca"]
13
10
  s.homepage = "https://github.com/at1as/BetteR"
14
11
  s.files = `git ls-files`.split("\n")
15
12
  s.executables << 'better_rest'
data/lib/better_rest.rb CHANGED
@@ -2,113 +2,150 @@
2
2
 
3
3
  require 'sinatra'
4
4
  require 'typhoeus'
5
+ require 'json'
5
6
 
6
7
  set :public_dir, File.expand_path('../../public', __FILE__)
7
8
  set :views, File.expand_path('../../views', __FILE__)
8
9
 
9
10
  helpers do
10
- include Rack::Utils
11
- alias_method :h, :escape_html
11
+ include Rack::Utils
12
+ alias_method :h, :escape_html
12
13
  end
13
14
 
14
- get '/?' do
15
- @requests = ["GET","POST","PUT","DELETE","HEAD","OPTIONS","PATCH"]
16
- @timeout = ["1","2","5","10","60"]
17
- @validHeaderCount = 1
18
- @headerHash = {"" => ""}
19
- @follow, @verbose, @ssl, @loggingOn = true, true, false, false
20
- @visible = ["displayed", "hidden", "displayed", "displayed", "displayed"] #Ordered display toggle for frontend: REQUEST, AUTH, HEADERS, PAYLOAD, RESULTS
21
- erb :index
22
- end
15
+ BETTER_SIGNATURE = "BetteR - https://github.com/at1as/BetteR"
23
16
 
24
- get '/env' do
25
- <<-ENDRESPONSE
26
- Ruby: #{RUBY_VERSION} <br/>
27
- Rack: #{Rack::VERSION} <br/>
28
- Sinatra: #{Sinatra::VERSION}
29
- ENDRESPONSE
17
+ get '/?' do
18
+ @requests = ["GET","POST","PUT","DELETE","HEAD","OPTIONS","PATCH"]
19
+ @times = ["1", "2", "5", "10"]
20
+ @timeout = ["1","2","5","10","60"]
21
+ @validHeaderCount = 1
22
+ @headerHash = {"" => ""}
23
+ @follow, @verbose, @ssl, @loggingOn = true, true, false, false
24
+ @visible = ["displayed", "hidden", "displayed", "displayed", "displayed"] #Ordered display toggle for frontend: REQUEST, AUTH, HEADERS, PAYLOAD, RESULTS
25
+ @payloadHeight = "100px"
26
+
27
+ erb :index
30
28
  end
31
29
 
32
30
  post '/' do
33
- @headerHash = {}
34
- @validHeaderCount = 1
35
- @formResponse = true
36
- @follow, @verbose, @ssl, @loggingOn = true, true, false, false
37
- @requestBody = ""
38
- @visible = [params[:serveURLDiv], params[:serveAuthDiv], params[:serveHeaderDiv], params[:servePayloadDiv], params[:serveResultsDiv]]
39
-
40
- (0..Integer(params[:headerCount])).each do |i|
41
- @keyIncrement = "key" + "#{i}"
42
- @valueIncrement = "value" + "#{i}"
43
-
44
- if params[@keyIncrement] and not params[@keyIncrement].empty? and params[@valueIncrement] and not params[@valueIncrement].empty?
45
- @headerHash[params[@keyIncrement]] = params[@valueIncrement]
46
- @validHeaderCount += 1
47
- end
48
- end
49
-
50
- if @headerHash["User-Agent"] == nil #add branded User-Agent header, only if empty
51
- @headerHash["User-Agent"] = "BetteR - https://github.com/at1as/BetteR"
52
- end
53
-
54
- if params[:followlocation] == ""
55
- @follow = false
56
- end
57
- if params[:verbose] == ""
58
- @verbose = false
59
- end
60
- if params[:ssl_verifypeer] == "on"
61
- @ssl = true
62
- end
63
- if params[:enableLogging] == "on"
64
- @loggingOn = true
65
- end
66
- unless params[:datafile].nil?
67
- @requestBody = { content: params[:payload], file: File.open(params[:datafile][:tempfile], 'r') }
68
- else
69
- @requestBody = { content: params[:payload] }
70
- end
71
-
72
- request = Typhoeus::Request.new(
73
- params[:url],
74
- method: params[:requestType],
75
- :username => params[:usr],
76
- :password => params[:pwd],
77
- :auth_method => :auto, #Should be manually set in order to test unideal APIs
78
- :headers => @headerHash,
79
- :body => @requestBody, #to replace -> body: params[:payload],
80
- followlocation: @follow,
81
- verbose: @verbose,
82
- ssl_verifypeer: @ssl,
83
- :timeout => Integer(params[:timeoutInterval])
84
- )
85
-
86
- request.run
87
- response = request.response
88
-
89
- if @headerHash["User-Agent"] == "BetteR - https://github.com/at1as/BetteR"
90
- @headerHash.delete("User-Agent")
91
- end
92
-
93
- if @loggingOn == true
94
- File.open('log/' + Time.now.strftime("%Y-%m-%d") + '.log', 'a') {
95
- |file| file.write("-"*10 + "\n" + Time.now.to_s + request.inspect + "\n\n" )
96
- }
97
- end
98
-
99
- puts params[:payload]
100
-
101
- @requestOptions = request.options
102
- @returnBody = response.body
103
- @returnCode = response.return_code
104
- @returnTime = response.time
105
- @statCodeReturn = response.response_headers
106
-
107
- @requests = ["#{params[:requestType]}", "GET","POST","PUT","DELETE","HEAD","OPTIONS","PATCH"].uniq
108
- @timeout = ["1","2","5","10","60"]
109
- erb :index
31
+ # Set Defaults
32
+ @headerHash = {}
33
+ @validHeaderCount = 1
34
+ @formResponse = true
35
+ @follow, @verbose, @ssl, @loggingOn = true, true, false, false
36
+ @requestBody = params[:payload]
37
+ @visible = [:servURLDiv, :servAuthDiv, :servHeaderDiv, :servePayloadDiv, :servResultsDiv].map{ |k| params[k] }
38
+ @var_key = params[:varKey]
39
+ @var_value = params[:varValue]
40
+ @ContentType = "text/plain"
41
+ @payloadHeight = params[:payloadHeight] ||= "100px"
42
+
43
+ puts "PH: #{@payloadHeight}"
44
+
45
+ # Loop through Header key/value pairs
46
+ # If a header is created and deleted in the UI before submit, headerCount will not renormalize (and will exceed the number headers sent)
47
+ # This will check that a particular header exists, before adding it to the Hash
48
+ params[:headerCount].to_i.times do |i|
49
+ @keyIncrement = "key#{i}"
50
+ @valueIncrement = "value#{i}"
51
+
52
+ if !(params.fetch(@keyIncrement, '').empty? || params.fetch(@valueIncrement, '').empty?)
53
+ @headerHash[params[@keyIncrement]] = params[@valueIncrement]
54
+ @validHeaderCount += 1
55
+ end
56
+ end
57
+
58
+ # Shameless branding. Only if User-Agent isn't user specified
59
+ @headerHash["User-Agent"] ||= BETTER_SIGNATURE
60
+
61
+ # Check which options the user set or default to the following
62
+ @follow = false if params[:followlocation] == ""
63
+ @verbose = false if params[:verbose] == ""
64
+ @ssl = true if params[:ssl_verifypeer] == "on"
65
+ @loggingOn = true if params[:enableLogging] == "on"
66
+
67
+ # For parallel Requests
68
+ hydra = Typhoeus::Hydra.new
69
+
70
+ # Create the Request (swap variable keys for values, if they have been set)
71
+ request = Typhoeus::Request.new(
72
+ params[:url].gsub("{{#{@var_key}}}", @var_value),
73
+ method: params[:requestType],
74
+ username: params[:usr].gsub("{{#{@var_key}}}", @var_value),
75
+ password: params[:pwd].gsub("{{#{@var_key}}}", @var_value),
76
+ auth_method: :auto, #Should ideally not be auto, in order to test unideal APIs
77
+ headers: @headerHash,
78
+ body: params[:payload].gsub("{{#{@var_key}}}", @var_value),
79
+ followlocation: @follow,
80
+ verbose: @verbose,
81
+ ssl_verifypeer: @ssl,
82
+ timeout: Integer(params[:timeoutInterval])
83
+ )
84
+
85
+ # Modify Request Payload to include datafile, if present
86
+ if params[:datafile]
87
+ @requestBody = { content: params[:payload], file: File.open(params[:datafile][:tempfile], 'r') }
88
+ request.options[:body] = @requestBody #{ content: params[:payload], file: File.open(params[:datafile][:tempfile], 'r') }
89
+ end
90
+
91
+ # Substitute Header Values for defined variables
92
+ request.options[:headers].each do |key, val|
93
+ if val.to_s.include? "{{#{@var_key}}}"
94
+ request.options[:headers][key.to_s] = val.gsub("{{#{@var_key}}}", @var_value)
95
+ end
96
+ end
97
+
98
+ # Remove unused fields from request (some APIs don't handle unexpected fields)
99
+ request.options.delete(:body) if request.options[:body] == ""
100
+ request.options.delete(:username) if params[:usr] == ""
101
+ request.options.delete(:password) if params[:pwd] == ""
102
+ request.options.delete(:auth_method) if params[:pwd] == "" && params[:usr] == ""
103
+
104
+ # Send the request (specified number of times)
105
+ params[:times].to_i.times.map{ hydra.queue(request) }
106
+ hydra.run
107
+ response = request.response
108
+
109
+ # If user-agent wasn't set by user, don't bother showing the user this default
110
+ request.options[:headers].delete('User-Agent') && @headerHash.delete("User-Agent") if @headerHash["User-Agent"] == BETTER_SIGNATURE
111
+
112
+ # Log the request response
113
+ if @loggingOn
114
+ File.open('log/' + Time.now.strftime("%Y-%m-%d") + '.log', 'a') do |file|
115
+ file.write("-" * 10 + "\n" + Time.now.to_s + request.inspect + "\n\n" )
116
+ end
117
+ end
118
+
119
+ # These values will be used by the ERB page
120
+ # Add the URL to the Request Options returned
121
+ request.options[:url] = request.url
122
+ @requestOptions = JSON.pretty_generate(request.options)
123
+ @returnBody = response.body
124
+ @returnCode = response.return_code
125
+ @returnTime = response.time
126
+ @statCodeReturn = response.response_headers
127
+ @requests = ["#{params[:requestType]}", "GET","POST","PUT","DELETE","HEAD","OPTIONS","PATCH"].uniq
128
+ @times = ["#{params[:times]}", "1", "2", "5", "10"].uniq
129
+ @timeout = ["1","2","5","10","60"]
130
+
131
+ erb :index
110
132
  end
111
133
 
112
134
  not_found do
113
- redirect '/'
135
+ redirect '/'
136
+ end
137
+
138
+ # Returns Ruby/Sinatra Environment details
139
+ get '/env' do
140
+ <<-ENDRESPONSE
141
+ Ruby: #{RUBY_VERSION} <br/>
142
+ Rack: #{Rack::VERSION} <br/>
143
+ Sinatra: #{Sinatra::VERSION}
144
+ ENDRESPONSE
145
+ end
146
+
147
+ # Kills process. Work around for Vegas Gem not catching SIGINT from Terminal
148
+ get '/quit' do
149
+ puts "\nExiting..."
150
+ exit!
114
151
  end
data/public/mainCSS.css CHANGED
@@ -1,39 +1,86 @@
1
- body {
1
+ /*Defaults*/
2
+ body {
2
3
  font-family:"Gill Sans", "Gill Sans MT", Sans-Serif;
3
4
  background-color: #FDFDFD;
4
5
  padding-bottom: 20px;
5
6
  margin: 0px;
6
- }
7
+ }
8
+ h1 {
9
+ font-size: 14px;
10
+ color: #999999;
11
+ font-style: normal;
12
+ font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
13
+ }
14
+ h2 {
15
+ font-size: 15px;
16
+ color: red;
17
+ display: inline-block;
18
+ font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
19
+ }
20
+ h2:hover{
21
+ color:black;
22
+ }
23
+ input{
24
+ width:46%;
25
+ border-radius: 2px;
26
+ background-color:#FEFEFE;
27
+ border-color: transparent;
28
+ box-shadow: 2px 1px 1px #DDDDDD;
29
+ font-family: Arial;
30
+ font-size: 13px;
31
+ }
32
+ textarea{
33
+ border-radius: 4px;
34
+ border-color: transparent;
35
+ background-color: #FDFDFD;
36
+ overflow:hidden;
37
+ min-height: 100px;
38
+ max-width: 98%;
39
+ min-width: 98%;
40
+ box-shadow: 2px 1px 1px #DDDDDD;
41
+ font-family: arial;
42
+ font-size: 13px;
43
+ }
44
+ li{
45
+ margin-left:20px;
46
+ margin-right:20px;
47
+ }
48
+ li a{
49
+ text-decoration: none;
50
+ padding-right: 20px;
51
+ padding-top: 6px;
52
+ padding-bottom: 6px;
53
+ padding-left: 20px;
54
+ border-radius: 3px;
55
+ background-color: #B9B9B9;
56
+ font-size: 12px;
57
+ color: #FFFFFF;
58
+ font-weight: normal;
59
+ font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
60
+ }
61
+ li a:hover{
62
+ color:black;
63
+ }
64
+
65
+ /*Classes*/
7
66
  .container{
8
- width: 555px;
67
+ max-width:700px;
9
68
  margin:10px auto 0px auto;
10
69
  }
11
70
  .forceInline{
12
71
  display:inline;
13
72
  }
14
- .backgroundText{
15
- text-align: center;
16
- color:#888888;
17
- }
18
-
19
73
  .width25{
20
74
  width:13%;
21
75
  padding:0px;
22
76
  }
23
77
  .widthRemainder{
24
78
  display: inline;
25
- width: 78%;
79
+ width: 70%;
26
80
  border: 2px 2px 2px 2px;
27
81
  border-radius: 2px;
28
82
  background-color:#FDFDFD;
29
83
  }
30
- .restrictedHeight{
31
- padding: 10px 4px 10px 4px;
32
- max-height: 200px;
33
- overflow: scroll;
34
- background-color: #F2F2F2;
35
- border-radius: 3px;
36
- }
37
84
  .close {
38
85
  display: inline;
39
86
  font-size: 12px;
@@ -49,9 +96,9 @@ body {
49
96
  border-radius: 7px;
50
97
  background-color: #CCCCCC;
51
98
  }
52
-
99
+ /*minimal isn't used yet*/
53
100
  .minimal{
54
- padding:0px;
101
+ padding:0px;
55
102
  }
56
103
  .box{
57
104
  padding:5px 5px 5px 5px;
@@ -59,100 +106,52 @@ body {
59
106
  border-radius: 4px;
60
107
  border-style: solid;
61
108
  border-color: #CFCFCF;
62
- border-width: 1px;
109
+ border-width: 1px;
63
110
  transition: 90s;
64
111
  box-shadow: 2px 1px 1px #CCCCCC;
65
-
66
- }
67
- .minmax:hover{
68
- color:black;
69
- }
70
- h1 {
71
- font-size: 14px;
72
- color: #999999;
73
- font-style: normal;
74
- font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
75
112
  }
76
- h2 {
77
- font-size: 15px;
78
- color: red;
79
- display: inline-block;
80
- font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
81
- /*padding: 12px 0 0px 0;*/
82
- }
83
- .holdValue {
84
- transition: 0s 9999999s;
113
+ .modal{
114
+ background-color: #CCCCCC;
115
+ opacity:1.0;
116
+ position: fixed;
117
+ top: 25%;
118
+ left: 50% ;
119
+ width:280px;
120
+ margin-left:-140px;
121
+ padding:20px;
122
+ box-shadow: 2px 1px 1px #DDDDDD;
123
+ z-index:11;
85
124
  }
86
- div:active {
87
- transition:90s;
125
+ .header-button {
126
+ color:#FFFFFF;
127
+ background-color: #000000;
88
128
  }
89
129
 
90
- #submit {
91
- border:none;
92
- background:#888888;
93
- margin-top: 8px;
94
- padding: 4px 12px 4px 12px;
95
- border-radius: 3px;
96
- color: white;
97
- float: right;
98
- margin-left: 10px;
99
- box-shadow: 2px 2px 1px #DDDDDD;
100
- }
101
- #submit:hover{
102
- color:black;
130
+ .header-button:hover {
131
+ color:#999999;
132
+ background-color: #000000;
103
133
  }
104
- #clearBtn{
105
- border:none;
106
- background:#ff4b33;
107
- margin-top: 8px;
134
+ .submit {
135
+ border:none;
136
+ background:#888888;
137
+ margin-top: 8px;
108
138
  padding: 4px 12px 4px 12px;
109
139
  border-radius: 3px;
110
- font-weight: bold;
111
140
  color: white;
112
141
  float: right;
113
142
  margin-left: 10px;
114
143
  box-shadow: 2px 2px 1px #DDDDDD;
115
144
  }
116
- #clearBtn:hover{
145
+ .submit:hover{
117
146
  color:black;
118
147
  }
119
- #variables{
120
- border:none;
121
- background:#ff4b33;
122
- margin-top: 8px;
123
- padding: 4px 12px 4px 12px;
124
- border-radius: 3px;
125
- font-weight: bold;
126
- color: white;
127
- float: right;
128
- margin-left: 10px;
129
- box-shadow: 2px 2px 1px #DDDDDD;
130
- }
131
- #variables:hover{
132
- color:black;
133
- }
134
- input{
135
- width:46%;
136
- border-radius: 2px;
137
- background-color:#FEFEFE;
138
- border-color: transparent;
139
- box-shadow: 2px 1px 1px #DDDDDD;
140
- font-family: Arial;
141
- font-size: 13px;
142
- }
143
- textarea{
144
- border-radius: 4px;
145
- border-color: transparent;
146
- background-color: #FDFDFD;
147
- overflow:hidden;
148
- min-height: 80px;
149
- max-width: 98%;
150
- min-width: 98%;
151
- box-shadow: 2px 1px 1px #DDDDDD;
152
- font-family: arial;
153
- font-size: 13px;
148
+ .checkbox{
149
+ width:45px;
150
+ border:none;
151
+ box-shadow: none;
154
152
  }
155
153
 
154
+ /*By ID*/
156
155
  #add{
157
156
  color:white;
158
157
  background-color: #B9B9B9;
@@ -168,40 +167,6 @@ textarea{
168
167
  #dialog-modal{
169
168
  visibility: none;
170
169
  }
171
- ul{
172
- margin: 5px 5px 0px 5px;
173
- padding: 0;
174
- text-align: left;
175
-
176
- }
177
- li {
178
- min-width: 200px;
179
- }
180
- li a{
181
- text-decoration: none;
182
- text-align: left;
183
- padding-right: 20px;
184
- padding-top: 2px;
185
- padding-bottom: 2px;
186
- padding-left: 20px;
187
- margin-right: 10px;
188
- border-radius: 3px;
189
- background-color: #B9B9B9;
190
- font-size: 12px;
191
- color: #FFFFFF;
192
- font-weight: normal;
193
- font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
194
- }
195
-
196
- li a:hover{
197
- color:black;
198
- }
199
- .resultsBoxHead {
200
- visibility: none;
201
- }
202
- .resultsBoxcURL {
203
- visibility: none;
204
- }
205
170
  #dialog-background-blur{
206
171
  background-color: #EEEEEE;
207
172
  opacity: 0.85;
@@ -212,46 +177,18 @@ li a:hover{
212
177
  height:100%;
213
178
  z-index: 10;
214
179
  }
215
-
216
- #load-dialog-modal{
217
- background-color: #CCCCCC;
218
- opacity:1.0;
219
- position: fixed;
220
- top: 25%;
221
- left: 50% ;
222
- width:280px;
223
- margin-left:-140px;
224
- padding:20px;
225
- box-shadow: 2px 1px 1px #DDDDDD;
226
- z-index:11;
227
- }
228
-
229
- #file-upload-modal {
230
- background-color: #CCCCCC;
231
- opacity:1.0;
232
- position: fixed;
233
- top: 25%;
234
- left: 50% ;
235
- width:280px;
236
- margin-left:-140px;
237
- padding:20px;
238
- box-shadow: 2px 1px 1px #DDDDDD;
239
- z-index:11;
240
- }
241
-
242
180
  #header{
243
181
  background-color:black;
244
182
  color:white;
245
- padding-top:3px;
246
- padding-bottom:3px;
183
+ padding-top:5px;
184
+ padding-bottom:5px;
247
185
  }
248
-
249
- #settingsbutton {
250
- color:#999999;
251
- background-color: #000000;
186
+ #quit-button {
187
+ box-shadow: none;
188
+ font-weight: bold;
189
+ }
190
+ #datafile{
191
+ width:100%;
192
+ background-color:#CCCCCC;
193
+ box-shadow:none;
252
194
  }
253
-
254
- label {
255
- font-family: "Helvetica";
256
- font-size:14px;
257
- }
data/views/index.erb CHANGED
@@ -5,6 +5,7 @@
5
5
  <title>BetteR &mdash; A REST API Testing Utility</title>
6
6
  <link rel="shortcut icon" href="favicon.ico">
7
7
  <link rel="stylesheet" href="mainCSS.css">
8
+ <script src="page_actions.js" type="text/javascript"></script>
8
9
  </head>
9
10
 
10
11
  <body>
@@ -13,11 +14,19 @@
13
14
  <div id="header-title" style="display:inline-block">
14
15
  <h1 style="min-width:100%;">BetteR &mdash; A REST API Testing Utility.</h1>
15
16
  </div>
16
- <div style="display:inline-block; float:right; margin-left:10px;">
17
- <div id="settings-button" onclick="modalToggle('load-dialog-modal')" style="height:100%; margin-top:8px; display:inline-block">Settings</div>
17
+ <div style="display:inline-block; float:right; margin-right:10px;">
18
+ <form id="form0" name="quit-application" method="get" action="/quit" target="_self" enctype="multipart/form-data">
19
+ <input type="submit" class="header-button" value="Quit" id="quit-button" style="height:100%; margin-top:8px; display:inline-block; width:40px;">
20
+ </form>
21
+ </div>
22
+ <div style="display:inline-block; float:right; margin-left:10px; margin-right:10px;">
23
+ <div id="settings-button" class="header-button" onclick="modalToggle('load-dialog-modal')" style="height:100%; margin-top:8px; display:inline-block">Settings</div>
24
+ </div>
25
+ <div style="display:inline-block; float:right; margin-left:10px; margin-right:10px;">
26
+ <div id="file-upload-button" class="header-button" onclick="modalToggle('file-upload-modal')" style="height:100%; margin-top:8px; display:inline-block">File Upload</div>
18
27
  </div>
19
28
  <div style="display:inline-block; float:right; margin-right:10px;">
20
- <div id="file-upload-button" onclick="modalToggle('file-upload-modal')" style="height:100%; margin-top:8px; display:inline-block">File Upload</div>
29
+ <div id="variables-button" class="header-button" onclick="modalToggle('variables-modal')" style="height:100%; margin-top:8px; display:inline-block">Variables</div>
21
30
  </div>
22
31
  </div>
23
32
  </div>
@@ -33,11 +42,20 @@
33
42
  <div class="box" id="path">
34
43
  <select id="requestType" name="requestType">
35
44
  <% @requests.each do |request| %>
36
- <option value=<%= request %>><%= request %></option>
45
+ <option value="<%= request %>"><%= request %></option>
37
46
  <% end %>
38
47
  </select>
39
48
  <input type="text" value="<%= h(params[:url]) %>" name="url" id="url" placeholder=" URL" class="widthRemainder"/>
40
- <div class="close" id="closeURL" onclick="clearURL()">X</div>
49
+ <select id="times" name="times">
50
+ <% @times.each do |number| %>
51
+ <% if number == "1" %>
52
+ <option value="<%= number %>"><%= number %> time</option>
53
+ <% else %>
54
+ <option value="<%= number %>"><%= number %> times</option>
55
+ <% end %>
56
+ <% end %>
57
+ </select>
58
+ <div class="close" id="closeURL" onclick="clearURL()">X</div>
41
59
  </div>
42
60
  </div>
43
61
  <div>
@@ -49,18 +67,32 @@
49
67
  <h2><div class="head" id="headingAuth" onclick="toggleAuthVisibility()">[&ndash;] Authentication</div></h2>
50
68
  <div class="box" id="auth">
51
69
  <div id="authSelect">
52
- <span style="display:inline-block; white-space:nowrap; margin-top:5px;margin-bottom:5px;">
70
+ <span style="display:inline-block; white-space:nowrap; margin-top:5px;margin-bottom:5px;">
53
71
  <label for="basicAuthSelect">
54
- <input id="basicAuthSelect" type="radio" name="authType" value="basic" checked="true" style="width:14px;">Basic
72
+ <input id="basicAuthSelect" type="radio" name="authType" value="basic" onclick="oAuthHideFields()" checked="true" style="width:20px;">Basic
55
73
  </label>
56
74
  <label for="digestAuthSelect">
57
- <input id="digestAuthSelect" type="radio" name="authType" value="digest" style="width:14px;">Digest
75
+ <input id="digestAuthSelect" type="radio" name="authType" value="digest" onclick="oAuthHideFields()" style="width:20px;">Digest
76
+ </label>
77
+ <!-- Not yet supported. OAuth is a pain...
78
+ <label for="oAuthSelect">
79
+ <input id="oAuthSelect" type="radio" name="authType" value="oauth" onclick="oAuthShowFields()"style="width:20px;">OAuth</input>
58
80
  </label>
81
+ <label for="oAuth2Select">
82
+ <input id="oAuth2Select" type="radio" name="authType" value="oauth2" onclick="oAuthShowFields()"style="width:20px;">OAuth2</input>
83
+ </label>
84
+ -->
59
85
  </span>
60
86
  </div>
61
87
  <input type="text" value="<%=h(params[:usr])%>" name="usr" id="usr" placeholder=" Username" />
62
88
  <input type="text" value="<%=h(params[:pwd])%>" name="pwd" id="pwd" placeholder=" Password" />
63
89
  <div class="close" id="closeAuth" onclick="clearAuthCredentials()">X</div>
90
+ <input type="text" value="<%=h(params[:api_key])%>" name="api_key" id="api_key" placeholder=" API Key" style="display:none;" />
91
+ <input type="text" value="<%=h(params[:secret])%>" name="secret" id="secret" placeholder=" Shared Secret" style="display:none;" />
92
+ <input type="text" value="<%=h(params[:callback])%>" name="callback" id="callback" placeholder=" Callback URL" style="display:none;" />
93
+ <input type="text" value="<%=h(params[:callback])%>" name="callback" id="callback" placeholder=" Callback URL" style="display:none;" />
94
+ <input type="text" value="<%=h(params[:callback])%>" name="callback" id="callback" placeholder=" Callback URL" style="display:none;" />
95
+ <input type="text" value="<%=h(params[:callback])%>" name="callback" id="callback" placeholder=" Callback URL" style="display:none;" />
64
96
  </div>
65
97
  </div>
66
98
  <div>
@@ -77,9 +109,9 @@
77
109
  <div id="headerfields<%= index %>" style="margin-bottom:2px;" >
78
110
  <input type="text" value="<%=key%>" name="key<%=index%>" id="key<%=index%>" placeholder=" Name" class="key" />
79
111
  <input type="text" value="<%=value%>" name="value<%=index%>" id="value<%=index%>" placeholder=" Value" class="value" />
80
- <div class="close" id="close<%= index %>" onclick="removeRow(this)">X</div>
112
+ <div class="close" id="close<%= index %>" onclick="removeRow(this)">X</div>
81
113
  </div>
82
- <% end %>
114
+ <% end %>
83
115
  </div>
84
116
  <div>
85
117
  <input type="button" value="Add<%=h(params[:add])%>" id="add" class="width25" onclick="addNewHeader()"/>
@@ -94,14 +126,14 @@
94
126
  <% end %>
95
127
  <h2><div class="head" id="headingData" onclick="toggleDataVisibility()">[&ndash;] Payload</div></h2>
96
128
  <div class="box" id="data">
97
- <textarea value="<%=h(params[:payload])%>" name="payload" id="payload" placeholder=" Payload Data"><%=h(params[:payload])%></textarea>
98
- </div>
129
+ <textarea value="<%=h(params[:payload])%>" name="payload" id="payload" placeholder=" Payload Data" style="height:<%= @payloadHeight %>"><%=h(params[:payload])%></textarea>
130
+ </div>
99
131
  </div>
100
132
  <div style="margin-top:5px, padding-top: 3px, padding-bottom: 4px">
101
- <input type="submit" value="Send" id="submit" class="width25" onclick="prepareSubmission()" style="margin-bottom:10px;"/>
102
- <input type="button" value="Clear All" id="submit" class="width25" onclick="clearAllFields()" style="margin-bottom:10px;"/>
133
+ <input type="submit" value="Send" id="submit" class="submit width25" onclick="setHeight()" style="margin-bottom:10px;"/>
134
+ <input type="button" value="Clear All" id="submit" class="submit width25" onclick="clearAllFields()" style="margin-bottom:10px;"/>
103
135
  </div>
104
- <% if @formResponse == true %>
136
+ <% if @formResponse == true %>
105
137
  <div>
106
138
  <% if @visible[4] == "hidden"%>
107
139
  <input type="hidden" id="serveResultsDiv" name="serveResultsDiv" value="hidden">
@@ -110,54 +142,62 @@
110
142
  <% end %>
111
143
  <h2><div class="head" id="headingResults" style="margin-top:10px" onclick="toggleResultsVisibility()">[&ndash;] Results</div></h2>
112
144
  <div class="box" id="results">
113
- <ul>
114
- <li style="display:inline;" id="viewResponseTab">
145
+ <div style="margin-left:15px; margin-top: 15px; margin-bottom: 15px;">
146
+ <b>Request Time:</b> <%= @returnTime.to_s %> seconds<br/>
147
+ <b>Return Code:</b> <%= @returnCode.to_s %>
148
+ </div>
149
+ <div style="padding: 0px;">
150
+ <ul style="margin-left:0px; padding-left:0px; text-align:center">
151
+ <li style="display:inline-block;" id="viewResponseTab">
115
152
  <a onclick="hideReq()" id="responseDataText" style="color:#000000">Response Data</a>
116
153
  </li>
117
- <li style="display:inline" id="viewResponseHeadersTab">
118
- <a onclick="hideRespData()"id="responseHeaderText">Response Headers</a>
154
+ <li style="display:inline-block;" id="viewResponseHeadersTab">
155
+ <a onclick="hideRespData()" id="responseHeaderText">Response Headers</a>
119
156
  </li>
120
- <li style="display:inline" id="viewRequestTab">
121
- <a onclick="hideResp()" id="requestHeaderText">Request Body</a>
157
+ <li style="display:inline-block;" id="viewRequestTab">
158
+ <a onclick="hideResp()" id="requestHeaderText">Request Params</a>
122
159
  </li>
123
160
  </ul>
124
- <div >
125
- <textarea style="min-height:180px; margin-top:10px; overflow:scroll" id="resultsBox"><%= @returnBody.to_s %>
126
- &#10----&#10Response: <%= @returnCode.to_s %> &#10Request Time: <%= @returnTime.to_s %> seconds
161
+ </div>
162
+ <div>
163
+ <textarea style="min-height:180px; overflow:scroll" id="resultsBox"><%= h @returnBody %>
164
+ </textarea>
165
+ <textarea style="min-height:180px; overflow:scroll; display:none; font-size:15px;" id="resultsBoxHead"><%= @statCodeReturn.to_s %>
166
+ </textarea>
167
+ <textarea style="min-height:180px; overflow:scroll; display:none; font-size:15px;" id="resultsBoxcURL"><%= @requestOptions.to_s %>
127
168
  </textarea>
128
- <textarea style="min-height:180px; margin-top:10px; overflow:scroll; display:none" id="resultsBoxHead"><%= @statCodeReturn.to_s %></textarea>
129
- <textarea style="min-height:180px; margin-top:10px; overflow:scroll; display:none" id="resultsBoxcURL"><%= @requestOptions.to_s %></textarea>
130
169
  </div>
131
170
  </div>
132
171
  </div>
133
172
  <% end %>
173
+
134
174
  <!-- MODAL GRAY BACKGROUND -->
135
175
  <div id="dialog-background-blur" style="visibility:hidden" onclick="modalHideAll()"></div>
136
- <!-- BEGIN SETTINGS MODAL-->
137
- <div id="load-dialog-modal" title="Settings" style="border-radius:4px; visibility:hidden" onclick="returnFalse(event)">
176
+ <!-- BEGIN SETTINGS MODAL-->
177
+ <div id="load-dialog-modal" class="modal" title="Settings" style="border-radius:4px; visibility:hidden" onclick="returnFalse(event)">
138
178
  <p style="font-size:15px; margin-top:0px"><strong>Configuration:</strong></p>
139
179
  <div style="display:inline-block;width:100%">
140
- <label for="followlocation">
141
- <input type="checkbox" name="followlocation" id="followlocation" style="float:right"
142
- <% if @follow == true %>checked<% end %>>
143
- Follow Redirects?<br/>
144
- </label>
145
- <label for="verbose">
146
- <input type="checkbox" name="verbose" id="verbose" style="float:right"
147
- <% if @verbose == true %>checked<% end %>>
148
- Verbose Response?<br/>
149
- </label>
150
- <label for="ssl_verifypeer">
151
- <input type="checkbox" name="ssl_verifypeer" id="ssl_verifypeer" style="float:right"
152
- <% if @ssl == true %>checked<% end %>>
153
- Verify SSL Peers?<br/>
154
- </label>
155
- <label for="enableLogging">
156
- <input type="checkbox" name="enableLogging" id="enableLogging" style="float:right"
157
- <% if @loggingOn == true %>checked<% end %>>
158
- Log Requests?<br/>
159
- </label>
160
- <label for="timeoutInterval">
180
+ <div>
181
+ <label for="followlocation">Follow Redirects?</label>
182
+ <input type="checkbox" name="followlocation" id="followlocation" class="checkbox" style="float:right"
183
+ <% if @follow == true %>checked<% end %>>
184
+ </div>
185
+ <div>
186
+ <label for="verbose">Verbose Response?</label>
187
+ <input type="checkbox" name="verbose" id="verbose" class="checkbox" style="float:right"
188
+ <% if @verbose == true %>checked<% end %>>
189
+ </div>
190
+ <div>
191
+ <label for="ssl_verifypeer">Verify SSL Peers?</label>
192
+ <input type="checkbox" name="ssl_verifypeer" id="ssl_verifypeer" class="checkbox" style="float:right"
193
+ <% if @ssl == true %>checked<% end %>>
194
+ </div>
195
+ <div>
196
+ <label for="enableLogging">Log Requests?</label>
197
+ <input type="checkbox" name="enableLogging" id="enableLogging" class="checkbox" style="float:right"
198
+ <% if @loggingOn == true %>checked<% end %>>
199
+ </div>
200
+ <label for="timeoutInterval"></label>
161
201
  <select id="timeoutInterval" name="timeoutInterval" style="float:right">
162
202
  <% @timeout.each do |interval| %>
163
203
  <option value=<%= interval %>
@@ -170,24 +210,40 @@
170
210
  </div>
171
211
  </div>
172
212
  <!-- END SETTINGS MODAL -->
213
+
173
214
  <!-- BEGIN FILE UPLOAD MODAL -->
174
- <!--<div id="dialog-background-blur" style="visibility:hidden" onclick="modalToggle('file-upload-modal')">-->
175
- <div id="file-upload-modal" title="File Upload" style="border-radius:4px; visibility:hidden" onclick="returnFalse(event)">
215
+ <div id="file-upload-modal" class="modal" title="File Upload" style="border-radius:4px; visibility:hidden" onclick="returnFalse(event)">
176
216
  <p style="font-size:15px; margin-top:0px"><strong>Attach File to Request:</strong></p>
177
217
  <div>
178
- <input type="file" id="datafile" name="datafile" style="width:100%; background-color:#CCCCCC; box-shadow:none;">
218
+ <input type="file" id="datafile" name="datafile">
219
+ <div id="clearFileUpload" onclick="clearFileUpload()" style="float:right;">Clear</div>
220
+ </div>
221
+ </div>
222
+ <!-- END FILE UPLOAD MODAL -->
223
+
224
+ <!-- BEGIN VARIABLES MODAL -->
225
+ <div id="variables-modal" class="modal" title="Variables" style="border-radius:4px; visibility:hidden" onclick="returnFalse(event)">
226
+ <p style="font-size:15px; margin-top:0px"><strong>Variables:</strong></p>
227
+ <div>
228
+ Will swap any instances of: <br/>
229
+ <div style="margin-left:auto; margin-right:auto; margin-top:10px; margin-bottom:10px;">
230
+ <b>{{Key}}</b> for <b>Value</b>
231
+ </div>
232
+ that appear within the request. <i>Note:</i> will not work for Header Keys
179
233
  </div>
180
- <div style="margin-top:10px;">
181
- <input type="button" value=" OK" onclick="modalToggle('file-upload-modal')">
234
+ <div style="margin-top:20px;">
235
+ <input type="text" value="<%=h(params[:varKey])%>" name="varKey" id="varKey" placeholder=" Key" />
236
+ <input type="text" value="<%=h(params[:varValue])%>" name="varValue" id="varValue" placeholder=" Value" />
182
237
  </div>
238
+ <div id="clearVariables" onclick="clearVariables()" style="float:right;">Clear</div>
183
239
  </div>
184
- <!--</div> -->
185
- <!-- END FILE UPLOAD MODAL -->
240
+ <!-- END VARIABLES MODAL -->
241
+ <input type="hidden" id="payloadHeight" name="payloadHeight" value="100">
242
+ <input type="hidden" id="responseHeight" name="payloadHeight" value="180">
186
243
  </form>
187
244
  </div>
188
245
 
189
- <script type="text/javascript" >
190
-
246
+ <script>
191
247
  /*Toggle Modal display on page*/
192
248
  function modalToggle(modal_id) {
193
249
  bgrnd = document.getElementById("dialog-background-blur");
@@ -200,9 +256,10 @@
200
256
  document.getElementById("dialog-background-blur").style.visibility = "hidden";
201
257
  document.getElementById("load-dialog-modal").style.visibility = "hidden";
202
258
  document.getElementById("file-upload-modal").style.visibility = "hidden";
259
+ document.getElementById("variables-modal").style.visibility = "hidden";
203
260
  }
204
261
 
205
- /*Re-serve minimised sections minimised on page reload. Note data from fields is always submitted*/
262
+ /*Re-serve minimised sections minimised on page reload. Note data from fields is always submitted*/
206
263
  if (document.getElementById("serveURLDiv").value == "hidden") {
207
264
  toggleRequestVisibility("arg1");
208
265
  }
@@ -275,17 +332,23 @@
275
332
  function clearAllFields() {
276
333
  document.getElementById("requestType").value = "GET";
277
334
  document.getElementById("url").value = "";
278
- document.getElementById("usr").value = "";
335
+ document.getElementById("usr").value = "";
279
336
  document.getElementById("pwd").value = "";
280
337
  document.getElementById("payload").value = "";
338
+ document.getElementById("varKey").value = "";
339
+ document.getElementById("varValue").value = "";
340
+ document.getElementById("payload").style.height = "100px";
281
341
  if (document.getElementById("resultsBox")){
282
342
  document.getElementById("resultsBox").value = "";
343
+ document.getElementById("resultsBox").style.height = "180px";
283
344
  }
284
345
  if (document.getElementById("resultsBoxHead")) {
285
346
  document.getElementById("resultsBoxHead").value = "";
347
+ document.getElementById("resultsBoxHead").style.height = "180px";
286
348
  }
287
349
  if (document.getElementById("resultsBoxcURL")) {
288
350
  document.getElementById("resultsBoxcURL").value = "";
351
+ document.getElementById("resultsBoxcURL").style.height = "180px";
289
352
  }
290
353
  while (headerfieldsAll.firstChild) {
291
354
  headerfieldsAll.removeChild(headerfieldsAll.firstChild);
@@ -298,7 +361,7 @@
298
361
  function addNewHeader() {
299
362
  clickCount += 1;
300
363
  document.getElementById("headerCount").value = clickCount + 1;
301
-
364
+
302
365
  var input0 = document.createElement('div');
303
366
  var input = document.createElement('input');
304
367
  var input2 = document.createElement('input');
@@ -344,6 +407,8 @@
344
407
 
345
408
  function clearURL(){
346
409
  document.getElementById('url').value = '';
410
+ document.getElementById('times').options.selectedIndex = 0;
411
+ document.getElementById('requestType').options.selectedIndex = 0;
347
412
  }
348
413
 
349
414
  function removeRow(rowNumber) {
@@ -378,12 +443,60 @@
378
443
  document.getElementById("requestHeaderText").style.color = "#000000";
379
444
  }
380
445
 
446
+ function oAuthShowFields() {
447
+ document.getElementById("usr").style.display = 'none';
448
+ document.getElementById("pwd").style.display = 'none';
449
+ document.getElementById("closeAuth").style.display = 'none';
450
+ document.getElementById("api_key").style.display = '';
451
+ document.getElementById("secret").style.display = '';
452
+ document.getElementById("callback").style.display = '';
453
+ }
454
+
455
+ function oAuthHideFields() {
456
+ document.getElementById("usr").style.display = '';
457
+ document.getElementById("pwd").style.display = '';
458
+ document.getElementById("closeAuth").style.display = '';
459
+ document.getElementById("api_key").style.display = 'none';
460
+ document.getElementById("secret").style.display = 'none';
461
+ document.getElementById("callback").style.display = 'none';
462
+ }
463
+
464
+ function clearFileUpload() {
465
+ var oldInput = document.getElementById("datafile")
466
+ var newInput = document.createElement('input');
467
+ newInput.id = oldInput.id;
468
+ newInput.type = oldInput.type;
469
+ newInput.name = oldInput.name;
470
+ oldInput.parentNode.replaceChild(newInput, oldInput);
471
+ }
472
+
473
+ function clearVariables() {
474
+ document.getElementById("varKey").value = "";
475
+ document.getElementById("varValue").value = "";
476
+ }
477
+
478
+ function setHeight() {
479
+ var payloadHeight = document.getElementById("payload").style.height;
480
+ document.getElementById("payloadHeight").value = payloadHeight;
481
+ if (document.getElementById("resultsBox")){
482
+ var resHeight = document.getElementById("resultsBox").style.height;
483
+ }
484
+ if (document.getElementById("resultsBoxHead")) {
485
+ var resHeight = document.getElementById("resultsBoxHead").style.height;
486
+ }
487
+ if (document.getElementById("resultsBoxcURL")) {
488
+ var resHeight = document.getElementById("resultsBoxHead").style.height;
489
+ }
490
+ document.getElementById("resultHeight").value = resHeight;
491
+ }
492
+
381
493
  /*Block some JS and Form behaviour from occuring*/
382
494
  function returnFalse(event) {
383
495
  event.cancelBubble=true;
384
496
  if(event.stopPropagation) { event.stopPropagation(); }
385
497
  return false;
386
498
  }
499
+
387
500
  </script>
388
501
  </body>
389
- </html>
502
+ </html>
metadata CHANGED
@@ -1,78 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: better_rest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Willems
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-01 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: sinatra
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ~>
18
- - !ruby/object:Gem::Version
19
- version: '1.4'
20
- - - '>='
21
- - !ruby/object:Gem::Version
22
- version: 1.4.4
23
- type: :runtime
24
- prerelease: false
25
- version_requirements: !ruby/object:Gem::Requirement
26
- requirements:
27
- - - ~>
28
- - !ruby/object:Gem::Version
29
- version: '1.4'
30
- - - '>='
31
- - !ruby/object:Gem::Version
32
- version: 1.4.4
33
- - !ruby/object:Gem::Dependency
34
- name: vegas
35
- requirement: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - ~>
38
- - !ruby/object:Gem::Version
39
- version: '0.1'
40
- - - '>='
41
- - !ruby/object:Gem::Version
42
- version: 0.1.11
43
- type: :runtime
44
- prerelease: false
45
- version_requirements: !ruby/object:Gem::Requirement
46
- requirements:
47
- - - ~>
48
- - !ruby/object:Gem::Version
49
- version: '0.1'
50
- - - '>='
51
- - !ruby/object:Gem::Version
52
- version: 0.1.11
53
- - !ruby/object:Gem::Dependency
54
- name: typhoeus
55
- requirement: !ruby/object:Gem::Requirement
56
- requirements:
57
- - - ~>
58
- - !ruby/object:Gem::Version
59
- version: '0.6'
60
- - - '>='
61
- - !ruby/object:Gem::Version
62
- version: 0.6.7
63
- type: :runtime
64
- prerelease: false
65
- version_requirements: !ruby/object:Gem::Requirement
66
- requirements:
67
- - - ~>
68
- - !ruby/object:Gem::Version
69
- version: '0.6'
70
- - - '>='
71
- - !ruby/object:Gem::Version
72
- version: 0.6.7
73
- description: A REST testing client delivered via Sinatra to any web browser.
11
+ date: 2014-08-29 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: This is a REST API test client accessible via the browser.
74
14
  email:
75
- - hello@jasonwillems.com
15
+ - jason@willems.ca
76
16
  executables:
77
17
  - better_rest
78
18
  extensions: []
@@ -97,12 +37,12 @@ require_paths:
97
37
  - lib
98
38
  required_ruby_version: !ruby/object:Gem::Requirement
99
39
  requirements:
100
- - - '>='
40
+ - - ">="
101
41
  - !ruby/object:Gem::Version
102
42
  version: '0'
103
43
  required_rubygems_version: !ruby/object:Gem::Requirement
104
44
  requirements:
105
- - - '>='
45
+ - - ">="
106
46
  - !ruby/object:Gem::Version
107
47
  version: '0'
108
48
  requirements: []