api_hammer 0.0.3 → 0.1.0

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: b422b307a5753a8315b2bce549a2a18966c78ede
4
- data.tar.gz: 9f23c48f532e57c59105da808f373879037640ff
3
+ metadata.gz: 30f42f8b22545e005c29603af5d98d6874e8027b
4
+ data.tar.gz: 7257d0076928ecc3c328596243c3b16d465dba6b
5
5
  SHA512:
6
- metadata.gz: 6edf87fe1bcac33ef5d2e74af2e93e366804d964a4f3ca0c6e581ab2e576b4698940eef276366e1aa728262fcdc7bd4ce00c406343f5d77597f7ebcd5957132d
7
- data.tar.gz: 4bfd01db70492fc17227e38bfac2f5dc622e6b4ebec1e228573a8ca23fd354e0f2f1fa7b95a52c764f46174d208ced4fb4ad99c963e11639553991580ac4741b
6
+ metadata.gz: a3ea4254d06322b584a4b78ec25d3334280c5118406913500cfaf8d2fbc84a9c5478fd6c0d2bfdb15ead42f795b58a9abc61bfa7daff88696195df93cd21f2d3
7
+ data.tar.gz: a275cccb8fba41c50c2781bc2423477bec6a688b0d831145ee044889193ab9d70105bf17a138d88cf3380ee4fbbd2216ad1ea42265609bef407729e90680468d
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ # 0.1.0
2
+ - Object#public_instance_exec
3
+ - Obect#public_instance_eval
4
+ - hc
5
+
1
6
  # 0.0.3
2
7
  - rake cucumber:pretty_json
3
8
  - Rails#find_or_halt
data/bin/hc ADDED
@@ -0,0 +1,220 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'faraday'
5
+ require 'logger'
6
+ require 'yaml'
7
+
8
+ # OPTION PARSER
9
+
10
+ require 'optparse'
11
+
12
+ # $options default values
13
+ $options = {
14
+ :verbose => true,
15
+ :color => nil,
16
+ :no_ssl_verify => false,
17
+ :headers => {},
18
+ }
19
+
20
+ $oauth = {}
21
+
22
+ opt_parser = OptionParser.new do |opts|
23
+ opts.banner = "Usage: #{$0} [options] <verb> <url> [body]"
24
+
25
+ opts.on("-v", "--[no-]verbose", "Run verbosely - output is like curl -v (this is the default)") do |v|
26
+ $options[:verbose] = v
27
+ end
28
+ opts.on("-q", "Run quietly - only outputs the response body (same as --no-verbose)") do |v|
29
+ $options[:verbose] = !v
30
+ end
31
+ opts.on("--[no-]color", "Color the output (defaults to color if the output device is a TTY)") do |v|
32
+ $options[:color] = v
33
+ end
34
+ opts.on("-t", "--content-type CONTENT-TYPE", "Sets the Content-Type header of the request") do |v|
35
+ $options[:headers]['Content-Type'.downcase] = v
36
+ end
37
+ opts.on("--oauth-token TOKEN") do |token|
38
+ $oauth[:token] = token
39
+ end
40
+ opts.on("--oauth-token-secret TOKEN_SECRET") do |token_secret|
41
+ $oauth[:token_secret] = token_secret
42
+ end
43
+ opts.on("--oauth-consumer-key CONSUMER_KEY") do |consumer_key|
44
+ $oauth[:consumer_key] = consumer_key
45
+ end
46
+ opts.on("--oauth-consumer-secret CONSUMER_SECRET") do |consumer_secret|
47
+ $oauth[:consumer_secret] = consumer_secret
48
+ end
49
+ opts.on("--oauth-signature-method SIGNATURE_METHOD") do |signature_method|
50
+ $oauth[:signature_method] = signature_method
51
+ end
52
+
53
+ opts.on("--no-ssl-verify", "Disables SSL verification - use cautiously!") do
54
+ $options[:no_ssl_verify] = true
55
+ end
56
+ opts.on("-H", "--header HEADER", "Set a header") do |header|
57
+ if header =~ /\A([^:]+):\s*(.*)\z/m # this could be more strictly conformant to rfc, but whatever
58
+ field_name = $1
59
+ field_value = $2
60
+ $options[:headers][field_name.downcase] = field_value
61
+ else
62
+ abort "bad header value given: #{header}"
63
+ end
64
+ end
65
+ end
66
+ opt_parser.parse!
67
+ abort(opt_parser.help) unless (2..3).include?(ARGV.size)
68
+
69
+ # OUTPUTTERS FOR FARADAY THAT SHOULD MOVE TO A LIB SOMEWHERE
70
+
71
+ # outputs the response body to the given output device (defaulting to STDOUT)
72
+ class FaradayOutputter < Faraday::Middleware
73
+ def initialize(app, outdev=STDOUT)
74
+ @app=app
75
+ @outdev = outdev
76
+ end
77
+
78
+ def call(request_env)
79
+ @app.call(request_env).on_complete do |response_env|
80
+ @outdev.puts(response_env[:body] || '')
81
+ end
82
+ end
83
+ end
84
+
85
+ # this is to approximate `curl -v`s output. but it's all faked, whereas curl gives you
86
+ # the real text written and read for request and response. whatever, close enough.
87
+ class FaradayCurlVOutputter < FaradayOutputter
88
+
89
+ # defines a method with the given name, applying coloring defined by any additional arguments.
90
+ # if $options[:color] is set, respects that; otherwise, applies color if the output device is a tty.
91
+ def self.color(name, *color_args)
92
+ define_method(name) do |arg|
93
+ if color?
94
+ require 'term/ansicolor'
95
+ color_args.inject(arg) do |result, color_arg|
96
+ Term::ANSIColor.send(color_arg, result)
97
+ end
98
+ else
99
+ arg
100
+ end
101
+ end
102
+ end
103
+
104
+ color :info, :intense_yellow
105
+ color :info_body, :yellow
106
+ color :protocol
107
+
108
+ color :request, :intense_cyan
109
+ color :request_verb, :bold
110
+ color :request_header
111
+ color :request_blankline, :intense_cyan, :bold
112
+
113
+ color :response, :intense_green
114
+ color :response_status, :bold, :green
115
+ color :response_header
116
+ color :response_blankline, :intense_green, :bold
117
+
118
+ def call(request_env)
119
+ @outdev.puts "#{info('*')} #{info_body("connect to #{request_env[:url].host} on port #{request_env[:url].port}")}"
120
+ @outdev.puts "#{info('*')} #{info_body("getting our SSL on")}" if request_env[:url].scheme=='https'
121
+ @outdev.puts "#{request('>')} #{request_verb(request_env[:method].to_s.upcase)} #{request_env[:url].request_uri} #{protocol('HTTP/1.1' || 'or something - TODO')}"
122
+ request_env[:request_headers].each do |k, v|
123
+ @outdev.puts "#{request('>')} #{request_header(k)}#{request(':')} #{v}"
124
+ end
125
+ @outdev.puts "#{request_blankline('>')} "
126
+ request_body = color_body_by_content_type(request_env[:body], request_env[:request_headers]['Content-Type'])
127
+ (request_body || '').split("\n", -1).each do |line|
128
+ @outdev.puts "#{request('>')} #{line}"
129
+ end
130
+ @app.call(request_env).on_complete do |response_env|
131
+ @outdev.puts "#{response('<')} #{protocol('HTTP/1.1' || 'or something - TODO')} #{response_status(response_env[:status].to_s)}"
132
+ request_env[:response_headers].each do |k, v|
133
+ @outdev.puts "#{response('<')} #{response_header(k)}#{response(':')} #{v}"
134
+ end
135
+ @outdev.puts "#{response_blankline ('<')} "
136
+ response_body = color_body_by_content_type(response_env[:body], response_env[:response_headers]['Content-Type'])
137
+ (response_body || '').split("\n", -1).each do |line|
138
+ @outdev.puts "#{response('<')} #{line}"
139
+ end
140
+ end
141
+ end
142
+
143
+ # whether to use color
144
+ def color?
145
+ $options[:color].nil? ? @outdev.tty? : $options[:color]
146
+ end
147
+
148
+ # a mapping for each registered CodeRay scanner to the Media Types which represent
149
+ # that language. extremely incomplete!
150
+ CodeRayForMediaTypes = {
151
+ :c => [],
152
+ :cpp => [],
153
+ :clojure => [],
154
+ :css => ['text/css', 'application/css-stylesheet'],
155
+ :delphi => [],
156
+ :diff => [],
157
+ :erb => [],
158
+ :groovy => [],
159
+ :haml => [],
160
+ :html => ['text/html'],
161
+ :java => [],
162
+ :java_script => ['application/javascript', 'text/javascript', 'application/x-javascript'],
163
+ :json => ['application/json'],
164
+ :php => [],
165
+ :python => ['text/x-python'],
166
+ :ruby => [],
167
+ :sql => [],
168
+ :xml => ['text/xml', 'application/xml', %r(\Aapplication/.*\+xml\z)],
169
+ :yaml => [],
170
+ }
171
+
172
+ # takes a body and a content type; returns the body, with coloring (ansi colors for terminals)
173
+ # possibly added, if it's a recognized content type and #color? is true
174
+ def color_body_by_content_type(body, content_type)
175
+ if body && color?
176
+ # kinda hacky way to get the media_type. faraday should supply this ...
177
+ require 'rack'
178
+ media_type = ::Rack::Request.new({'CONTENT_TYPE' => content_type}).media_type
179
+ coderay_scanner = CodeRayForMediaTypes.reject{|k,v| !v.any?{|type| type === media_type} }.keys.first
180
+ if coderay_scanner
181
+ require 'coderay'
182
+ body = CodeRay.scan(body, coderay_scanner).encode(:terminal)
183
+ end
184
+ end
185
+ body
186
+ end
187
+ end
188
+
189
+ # CONFIGURE THE FARADAY CONNECTION
190
+ faraday_options = {}
191
+ if $options[:no_ssl_verify]
192
+ faraday_options[:ssl] = {:verify => false}
193
+ end
194
+ connection = Faraday.new(faraday_options) do |builder|
195
+ if $oauth.any?
196
+ $oauth[:signature_method] ||= 'HMAC-SHA1'
197
+ require 'oauthenticator'
198
+ OAuthenticator::FaradaySigner
199
+ builder.use OAuthenticator::FaradaySigner, $oauth
200
+ end
201
+ builder.use $options[:verbose] ? FaradayCurlVOutputter : FaradayOutputter
202
+ builder.adapter Faraday.default_adapter
203
+ end
204
+
205
+ httpmethod, url, body = *ARGV
206
+
207
+ unless Faraday::Connection::METHODS.map{|m| m.to_s.downcase }.include?(httpmethod.downcase)
208
+ abort "Unrecognized HTTP method given: #{httpmethod}\n\n" + opt_parser.help
209
+ end
210
+
211
+ headers = $options[:headers]
212
+ if body && !headers['Content-Type'.downcase]
213
+ # I'd rather not have a default content-type, but if none is set then the HTTP adapter sets this to
214
+ # application/x-www-form-urlencoded anyway. application/json is a better default for our purposes.
215
+ headers['Content-Type'.downcase] = 'application/json'
216
+ end
217
+
218
+ # OH LOOK IT'S FINALLY ACTUALLY CONNECTING TO SOMETHING
219
+
220
+ response = connection.run_request(httpmethod.downcase.to_sym, url, body, headers)
@@ -0,0 +1,31 @@
1
+ class PublicForwarder < BasicObject
2
+ def initialize(object)
3
+ @object=object
4
+ end
5
+
6
+ # forwards public methods to the object. attempting to invoke private or
7
+ # protected methods raises, as it would if the object was a normal receiver.
8
+ def method_missing(method, *args, &block)
9
+ if @object.protected_methods.any?{|pm| pm.to_s == method.to_s }
10
+ ::Kernel.raise ::NoMethodError, "protected method `#{method}' called for #{@object.inspect}"
11
+ elsif @object.private_methods.any?{|pm| pm.to_s == method.to_s }
12
+ ::Kernel.raise ::NoMethodError, "private method `#{method}' called for #{@object.inspect}"
13
+ else
14
+ @object.__send__(method, *args, &block)
15
+ end
16
+ end
17
+ end
18
+
19
+ class Object
20
+ # like instance_exec, but only gives access to public methods. no private or protected methods, no
21
+ # instance variables.
22
+ def public_instance_exec(*args, &block)
23
+ PublicForwarder.new(self).instance_exec(*args, &block)
24
+ end
25
+
26
+ # like instance_eval, but only gives access to public methods. no private or protected methods, no
27
+ # instance variables.
28
+ def public_instance_eval(&block)
29
+ PublicForwarder.new(self).instance_eval(&block)
30
+ end
31
+ end
@@ -1,3 +1,3 @@
1
1
  module ApiHammer
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,43 @@
1
+ proc { |p| $:.unshift(p) unless $:.any? { |lp| File.expand_path(lp) == p } }.call(File.expand_path('.', File.dirname(__FILE__)))
2
+ require 'helper'
3
+
4
+ require 'api_hammer/public_instance_exec'
5
+
6
+ class Foo
7
+ def public_method(arg = :public)
8
+ arg
9
+ end
10
+ protected
11
+ def protected_method(arg = :protected)
12
+ arg
13
+ end
14
+ private
15
+ def private_method(arg = :private)
16
+ arg
17
+ end
18
+ end
19
+
20
+ describe '#public_instance_exec' do
21
+ it 'does things' do
22
+ foo = Foo.new
23
+ assert_equal(:public_exec, foo.public_instance_exec(:public_exec) { |arg| public_method(arg) })
24
+ regularex = (foo.protected_method rescue $!)
25
+ ex = assert_raises(regularex.class) { foo.public_instance_exec(:protected_exec) { |arg| protected_method(arg) } }
26
+ assert_equal(regularex.message, ex.message)
27
+ regularex = (foo.private_method rescue $!)
28
+ ex = assert_raises(regularex.class) { foo.public_instance_exec(:private_exec) { |arg| private_method(arg) } }
29
+ assert_equal(regularex.message, ex.message)
30
+ end
31
+ end
32
+ describe '#public_instance_eval' do
33
+ it 'does things' do
34
+ foo = Foo.new
35
+ assert_equal(:public, foo.public_instance_eval { public_method })
36
+ regularex = (foo.protected_method rescue $!)
37
+ ex = assert_raises(regularex.class) { foo.public_instance_eval { protected_method } }
38
+ assert_equal(regularex.message, ex.message)
39
+ regularex = (foo.private_method rescue $!)
40
+ ex = assert_raises(regularex.class) { foo.public_instance_eval { private_method } }
41
+ assert_equal(regularex.message, ex.message)
42
+ end
43
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: api_hammer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ethan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-02 00:00:00.000000000 Z
11
+ date: 2014-05-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: coderay
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rake
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -140,7 +154,8 @@ description: actually a set of small API-related tools. very much unlike a hamme
140
154
  at all, which is one large tool.
141
155
  email:
142
156
  - ethan@unth
143
- executables: []
157
+ executables:
158
+ - hc
144
159
  extensions: []
145
160
  extra_rdoc_files: []
146
161
  files:
@@ -150,9 +165,11 @@ files:
150
165
  - LICENSE.txt
151
166
  - README.md
152
167
  - Rakefile.rb
168
+ - bin/hc
153
169
  - lib/api_hammer.rb
154
170
  - lib/api_hammer/check_required_params.rb
155
171
  - lib/api_hammer/halt.rb
172
+ - lib/api_hammer/public_instance_exec.rb
156
173
  - lib/api_hammer/rails.rb
157
174
  - lib/api_hammer/request_logger.rb
158
175
  - lib/api_hammer/show_text_exceptions.rb
@@ -165,6 +182,7 @@ files:
165
182
  - test/check_required_params_test.rb
166
183
  - test/halt_test.rb
167
184
  - test/helper.rb
185
+ - test/public_instance_exec_test.rb
168
186
  - test/request_logger_test.rb
169
187
  - test/show_text_exceptions_test.rb
170
188
  - test/trailing_newline_test.rb
@@ -197,6 +215,7 @@ test_files:
197
215
  - test/check_required_params_test.rb
198
216
  - test/halt_test.rb
199
217
  - test/helper.rb
218
+ - test/public_instance_exec_test.rb
200
219
  - test/request_logger_test.rb
201
220
  - test/show_text_exceptions_test.rb
202
221
  - test/trailing_newline_test.rb