api_hammer 0.0.3 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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