http_fn 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5f163f75584cb8c3efd97c4086a5c6def7b7455ddd3a51325e4b205eff1c7932
4
+ data.tar.gz: 0d8c44e768a2cba2234c23294d1ac4bec17f78d3b792799387967438cd70e8a4
5
+ SHA512:
6
+ metadata.gz: 2d9f0607650dea8a96dd44491e4de2a91b7a87e947a30fdfde6c039002690e693ad0aed4695bb6ec734a9baf6c41247a005515370cda8623170a5c94f97e0cd6
7
+ data.tar.gz: 794d6bf88255e7329e62a2b817f98c7c85b694aca48ccc884b89bc253bd00888267de1d5b9ed86414a8ee2059387aad4563d8574b23df4f225f2db54e6bd24f6
@@ -0,0 +1,17 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ # These two are temporary
16
+ btrfly.rb
17
+ coucou.txt
@@ -0,0 +1 @@
1
+ 2.6
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in http_fn.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2017 Martin Chabot
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,160 @@
1
+ # HttpFn
2
+
3
+ Functional http client in Ruby.
4
+
5
+ ## Usage
6
+
7
+ ### Basics
8
+
9
+ #### The Request Structure
10
+
11
+ In order to query an HTTP server you will need to build a request hash.
12
+
13
+ Here's an example of a request:
14
+
15
+ ```ruby
16
+ {:proto=>"HTTP/1.1",
17
+ :host=>"http://api.github.com",
18
+ :path=>"/users/martinos/repos",
19
+ :query=>{},
20
+ :header=>
21
+ {"accept"=>"application/json",
22
+ "Content-Type"=>"application/json",
23
+ "user-agent"=>"paw/3.0.11 (macintosh; os x/10.11.6) gcdhttprequest"},
24
+ :method=>"GET",
25
+ :body=>""}
26
+ ```
27
+
28
+ To build that request you can use builder functions and the function composition operator ([`>>`](https://docs.ruby-lang.org/en/2.6.0/Proc.html#method-i-3E-3E)). Every builder function adds values to the response object. Example:
29
+
30
+ ```ruby
31
+ query = verb.("get") >>
32
+ with_path.("/users/martinos/repos") >>
33
+ with_host.("https://api.github.com") >>
34
+ add_headers.(json_headers)
35
+ ```
36
+ The `query` variable is a builder function that is created by combining multiple builder functions together.
37
+
38
+ This `query` function takes a hash as a parameter, and returns a hash decorated by the builders.
39
+
40
+ To demonstrate how it works, we need an initialized request (`empty_req`). Here's the `empty_req`:
41
+
42
+ ```ruby
43
+ pp empty_req
44
+ # =>
45
+ {:proto=>"HTTP/1.1",
46
+ :host=>"http://example.com",
47
+ :path=>"/",
48
+ :query=>{},
49
+ :header=>{},
50
+ :method=>"GET",
51
+ :body=>""}
52
+ ```
53
+
54
+ We apply the `empty_req` to the query that we've built.
55
+ ```ruby
56
+ pp query.(empty_req)
57
+ # =>
58
+ {:proto=>"HTTP/1.1",
59
+ :host=>"https://api.github.com",
60
+ :path=>"/users/martinos/repos",
61
+ :query=>{},
62
+ :header=>
63
+ {"accept"=>"application/json",
64
+ "Content-Type"=>"application/json",
65
+ "user-agent"=>"paw/3.0.11 (macintosh; os x/10.11.6) gcdhttprequest"},
66
+ :method=>"GET",
67
+ :body=>""}
68
+ ```
69
+ In order to `run` the query, you can combine the query with a "server" function (lambda) that takes a "request", sends it to the server and returns a http "response".
70
+
71
+ ```ruby
72
+ HttpFn::NetHttp.server.(query.(empty_req))
73
+
74
+ # =>
75
+ {:status=>"200",
76
+ :header=>
77
+ {"server"=>["GitHub.com"],
78
+ "date"=>["Sun, 04 Jun 2017 02:20:05 GMT"],
79
+ "content-type"=>["application/json; charset=utf-8"],
80
+ "vary"=>["Accept", "Accept-Encoding"],
81
+ ...},
82
+ }
83
+ :body => "{...}"
84
+ }
85
+
86
+ ```
87
+
88
+ ```ruby
89
+ (query >> HttpFn::NetHttp.server).(empty_req)
90
+ ```
91
+
92
+ Since a "server" is just a function that takes an HTTP request and returns an HTTP response, instead of using Net::Http interface you can use the `HttpFn::Rack.server` function that takes a rack app as parameter.
93
+
94
+ ```run
95
+ query >> HttpFn::Rack.server.(Rails.application)
96
+ ```
97
+
98
+ ## Middlewares
99
+
100
+ Since we are using composable functions to build our request and to query the web server, it's very easy to create our own "middlewares".
101
+
102
+ If we want to all the request and the response we can create a simple function such as:
103
+
104
+ ```
105
+ debug_fn = -> print, fn, input {
106
+ print.("Input: \n")
107
+ print.(input.to_s)
108
+ output = fn.(input)
109
+ print.("Output: \n")
110
+ print.(output)
111
+ output
112
+ }.curry
113
+
114
+ ```
115
+
116
+ the `print` param is a function that prints an object.
117
+
118
+ ```
119
+ printer = -> a { print a; a }
120
+ query >> debug_fn.(printer).(HttpFn::NetHttp.server)
121
+ ```
122
+
123
+ of course you can change the printer to print to the log file.
124
+
125
+ ```
126
+ printer = -> a { logger.debug(a) ; a }
127
+ ```
128
+
129
+ ### Curl, Httpie output
130
+
131
+ If you want to generate documentation with curl commands you can use a simple function such as:
132
+
133
+ ```
134
+ curl = -> a { puts HttpFn::Curl.req.(a) ; a }.curry
135
+ ```
136
+
137
+ Then you can use it with the query and the server function.
138
+
139
+ ```run
140
+ query >> curl >> HttpFn::NetHttp.server
141
+ ```
142
+
143
+ This will output:
144
+
145
+ ```
146
+ curl -X 'GET' 'https://api.github.com/users/martinos/repos?' \
147
+ -H 'accept: application/json' \
148
+ -H 'Content-Type: application/json' \
149
+ -H 'user-agent: ruby net/http'
150
+ ```
151
+
152
+
153
+
154
+ ## Contributing
155
+
156
+ 1. Fork it ( https://github.com/martinos/http_fn/fork )
157
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
158
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
159
+ 4. Push to the branch (`git push origin my-new-feature`)
160
+ 5. Create a new Pull Request
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
11
+
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'http_fn/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "http_fn"
8
+ spec.version = HttpFn::VERSION
9
+ spec.authors = ["Martin Chabot"]
10
+ spec.email = ["chabotm@gmail.com"]
11
+ spec.summary = %q{Http client that levrage the use of fp principle}
12
+ spec.description = %q{Http client that levrage the use of fp principle}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "minitest"
23
+ spec.add_dependency "rake", "~> 10.0"
24
+ spec.add_dependency "rack"
25
+ spec.add_dependency "fn_reader"
26
+ end
@@ -0,0 +1,43 @@
1
+ require "fn_reader"
2
+ require "uri"
3
+ require "base64"
4
+ require "http_fn/version"
5
+ require "http_fn/utils"
6
+
7
+ module HttpFn
8
+ include Utils
9
+
10
+ fn_reader :verb, :with_host, :with_path, :with_query, :withUri,
11
+ :with_json, :with_headers, :add_headers, :fetch, :to_curl,
12
+ :out_curl, :json_resp, :to_uri, :empty_req, :json_headers,
13
+ :with_basic_auth, :run_
14
+
15
+ @@empty_req = { proto: "HTTP/1.1", host: "http://example.com", path: "/", query: {}, header: {}, method: "GET", body: "" }
16
+ @@empty_resp = { status: nil, header: {}, body: {} }
17
+
18
+ @@run_ = -> fn { fn.(@@empty_req) } # underscore because run conflicts with run fn in minitest
19
+ @@verb = -> verb, req { req.merge({ method: verb.to_s.upcase }) }.curry
20
+ @@with_host = -> host, req { req[:host] = host; req }.curry
21
+ @@with_path = -> path, req { req[:path] = path; req }.curry
22
+ @@with_query = -> params, req { req[:query] = params; req }.curry
23
+ @@with_json = -> hash, req { req[:body] = hash.to_json; req }.curry
24
+ @@with_headers = -> header, req { req[:header] = header; req }.curry
25
+ @@add_headers = -> header, req { req[:header].merge!(header); req }.curry
26
+ @@with_basic_auth = -> user_name, pwd, req do
27
+ encoded = Base64.strict_encode64("#{user_name}:#{pwd}")
28
+ req.then(&add_headers.({ "Authorization" => "Basic #{encoded}" }))
29
+ end.curry
30
+
31
+ @@json_resp = Utils.at.(:body) >> Utils.parse_json
32
+ @@print = -> a { $stdout.puts a.pretty_inspect; a }
33
+ @@to_uri = -> req {
34
+ uri = URI(req.fetch(:host))
35
+ req[:query] && uri.query = URI.encode_www_form(req[:query])
36
+ uri.path = req[:path]
37
+ uri
38
+ }
39
+ @@json_headers =
40
+ { "accept" => "application/json",
41
+ "Content-Type" => "application/json",
42
+ "user-agent" => "paw/3.0.11 (macintosh; os x/10.11.6) gcdhttprequest" }
43
+ end
@@ -0,0 +1 @@
1
+ 2.4
@@ -0,0 +1,22 @@
1
+ require "net/http"
2
+ require "http_fn"
3
+
4
+ module HttpFn::Curl
5
+ include HttpFn
6
+
7
+ fn_reader :print_curl, :req
8
+
9
+ @@req = -> req {
10
+ first_part = %{curl -X '#{req[:method]}' '#{HttpFn::to_uri.(req).to_s}' #{req[:header].map(&@@header_to_curl).join(" ")}}
11
+ if req[:body] && !req[:body].empty?
12
+ first_part + %{\n\ -d $'#{req[:body].gsub("'", "\'")}'}
13
+ else
14
+ first_part
15
+ end
16
+ }
17
+ @@header_to_curl = -> a {
18
+ "\\\n -H '#{a[0]}: #{a[1]}'"
19
+ }
20
+
21
+ @@print_curl = -> req { $stdout.puts(to_curl.(req)); req }.curry
22
+ end
File without changes
@@ -0,0 +1,20 @@
1
+ require "net/http"
2
+ require "http_fn"
3
+
4
+ module HttpFn::Httpie
5
+ include HttpFn
6
+
7
+ fn_reader :print_curl, :req
8
+
9
+ @@req = -> req {
10
+ first_part = %{http #{req[:method]} '#{HttpFn::to_uri.(req).to_s}' #{req[:header].map(&@@header_to_httpie).join(" ")}}
11
+ if req[:body] && !req[:body].empty?
12
+ %{echo $'#{req[:body].gsub("'", "\'")}' |\\\n#{first_part}}
13
+ else
14
+ first_part
15
+ end
16
+ }
17
+ @@header_to_httpie = -> a {
18
+ "\\\n '#{a[0]}: #{a[1]}'"
19
+ }
20
+ end
@@ -0,0 +1,23 @@
1
+ require 'net/http'
2
+ require 'http_fn'
3
+
4
+ module HttpFn::NetHttp
5
+ include HttpFn
6
+ mattr_reader :method_str_to_req, :server, :net_resp
7
+
8
+ @@method_str_to_req = {"GET" => Net::HTTP::Get, "POST" => Net::HTTP::Post, "DELETE" => Net::HTTP::Delete, "PUT" => Net::HTTP::Put, "PATCH" => Net::HTTP::Patch}
9
+
10
+ @@server = -> req {
11
+ uri = to_uri.(req)
12
+ req_ = method_str_to_req.fetch(req.fetch(:method)).new(uri)
13
+ req_.set_body_internal(req[:body]) if req[:body]
14
+ header = req.fetch(:header)
15
+ header.each { |key, val| req_[key] = val }
16
+ http = Net::HTTP.new(uri.host, uri.port)
17
+ http.use_ssl = uri.scheme == 'https'
18
+ # http.set_debug_output($stdout)
19
+ @@net_resp.(http.request(req_))
20
+ }
21
+
22
+ @@net_resp = -> resp { {status: resp.code, header: resp.to_hash, body: resp.body} }
23
+ end
@@ -0,0 +1,13 @@
1
+ require "superators19"
2
+
3
+ class Proc
4
+ superator ">>~" do |fn|
5
+ -> a { fn.(self.(a)) }
6
+ end
7
+ end
8
+
9
+ class Object
10
+ superator ">>+" do |fn|
11
+ fn.(self)
12
+ end
13
+ end
@@ -0,0 +1,58 @@
1
+ require "http_fn"
2
+ require "pp"
3
+ #
4
+ # https://www.diffchecker.com/ihCGIKyG
5
+
6
+ module HttpFn::Rack
7
+ fn_reader :to_env, :server, :rack_resp_to_resp
8
+
9
+ @@server = -> rack { to_env >> rack.method(:call) >> rack_resp_to_resp }
10
+ @@to_env = -> request {
11
+ session ||= {}
12
+ session_options ||= {}
13
+
14
+ uri = request.then(&HttpFn.to_uri)
15
+ header = (request[:header] || {}).dup
16
+ body = request[:body] || ""
17
+
18
+ content_type_key, val = header.detect { |key, val| puts key; key.downcase == "content-type" }
19
+ env = {
20
+ # CGI variables specified by Rack
21
+ "REQUEST_METHOD" => request[:method].to_s.upcase,
22
+ "CONTENT_TYPE" => header.delete(content_type_key),
23
+ "CONTENT_LENGTH" => body.bytesize,
24
+ "PATH_INFO" => uri.path,
25
+ "QUERY_STRING" => uri.query || "",
26
+ "SERVER_NAME" => uri.host,
27
+ "SERVER_PORT" => uri.port,
28
+ "SCRIPT_NAME" => "",
29
+ }
30
+
31
+ env["HTTP_AUTHORIZATION"] = "Basic " + [uri.userinfo].pack("m").delete("\r\n") if uri.userinfo
32
+
33
+ # Rack-specific variables
34
+ env["rack.input"] = StringIO.new(body)
35
+ env["rack.errors"] = $stderr
36
+ env["rack.version"] = ::Rack::VERSION
37
+ env["rack.url_scheme"] = uri.scheme
38
+ env["rack.run_once"] = true
39
+ env["rack.session"] = session
40
+ env["rack.session.options"] = session_options
41
+
42
+ header.each { |k, v| env["HTTP_#{k.tr("-", "_").upcase}"] = v }
43
+ env
44
+ }
45
+
46
+ @@rack_resp_to_resp = -> resp {
47
+ { status: resp[0],
48
+ header: resp[1],
49
+ body: @@body_from_rack_response.(resp[2]) }
50
+ }
51
+
52
+ @@body_from_rack_response = -> response {
53
+ body = ""
54
+ response.each { |line| body << line }
55
+ response.close if response.respond_to?(:close)
56
+ body
57
+ }
58
+ end
@@ -0,0 +1,62 @@
1
+ require "json"
2
+ require "pp"
3
+ require "yaml"
4
+
5
+ module Utils
6
+ fn_reader :parse_json, :debug, :at, :retry_fn,
7
+ :record, :player, :count_by, :cache, :red, :time,
8
+ :expired, :apply, :and_then, :default, :map, :get, :try
9
+
10
+ @@parse_json = JSON.method(:parse)
11
+ @@debug = -> print, a, b { print.(a); print.(b.to_s); b }.curry
12
+ @@at = -> key, hash { hash[key] }.curry
13
+ @@red = -> a { "\033[31m#{a}\033[0m" }
14
+ # ( a -> b ) -> a -> b
15
+ @@try = -> f, a { a.nil? ? nil : f.(a) }.curry
16
+ @@retry_fn = -> fn, a {
17
+ begin
18
+ fn.(a)
19
+ rescue
20
+ sleep(1)
21
+ puts "RETRYING"
22
+ @@retry_fn.(fn).(a)
23
+ end
24
+ }.curry
25
+ @@record = -> filename, to_save {
26
+ File.open(filename, "w+") { |a| a << to_save.to_yaml }
27
+ to_save
28
+ }.curry
29
+ @@play = -> filename, _params { YAML.load(File.read(filename)) }.curry
30
+ # (Float -> String -> Bool) -> String -> (a -> b) -> b
31
+ @@cache = -> expired, filename, fn, param {
32
+ if expired.(filename)
33
+ @@record.(filename).(fn.(param))
34
+ else
35
+ puts "reading from cache"
36
+ @@play.(filename).(nil)
37
+ end
38
+ }.curry
39
+ @@expired = -> sec, a { !File.exist?(a) || (Time.now - File.mtime(a)) > sec }.curry
40
+ @@count_by = -> fn, a {
41
+ a.inject({}) do |res, a|
42
+ by = fn.(a)
43
+ res[by] ||= 0
44
+ res[by] += 1
45
+ res
46
+ end
47
+ }.curry
48
+
49
+ # (String -> String) -> String -> ( a -> b ) -> a -> b
50
+ @@time = -> print, msg, fn, a {
51
+ start_time = Time.now
52
+ res = fn.(a)
53
+ print.("Time duration for #{msg} = #{Time.now - start_time}")
54
+ res
55
+ }.curry
56
+ @@apply = -> method, a { a.send(method) }.curry
57
+ @@default = -> default, a { a.nil? ? default : a }.curry
58
+ @@and_then = -> f, a { a.nil? ? nil : f.(a) }.curry
59
+ @@map = -> f, enum { enum.map(&f) }.curry
60
+ @@at = -> key, hash { hash; hash[key] }.curry
61
+ @@get = -> method, obj { obj.send(method) }.curry
62
+ end
@@ -0,0 +1,3 @@
1
+ module HttpFn
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,28 @@
1
+ require 'minitest_helper'
2
+ require 'http_fn'
3
+ require 'http_fn/rack'
4
+ require 'http_fn/curl'
5
+
6
+ class HttpFn::CurlTest < Minitest::Test
7
+ include HttpFn
8
+
9
+ def setup
10
+ @curl = verb.("GET") >>~
11
+ with_path.("/coucou") >>~
12
+ with_headers.(json_headers) >>~
13
+ with_host.("https://api.github.com") >>~
14
+ with_json.({user: "martin"}) >>~
15
+ HttpFn::Curl.req >>+ run_
16
+ end
17
+
18
+ def test_should_return_a_curl_command
19
+ res = <<EOF
20
+ curl -X 'GET' 'https://api.github.com/coucou?' \\
21
+ -H 'accept: application/json' \\
22
+ -H 'Content-Type: application/json' \\
23
+ -H 'user-agent: paw/3.0.11 (macintosh; os x/10.11.6) gcdhttprequest'
24
+ -d $'{"user":"martin"}'
25
+ EOF
26
+ assert_equal res.chomp, @curl
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ require "minitest_helper"
2
+ require "http_fn"
3
+ require "http_fn/rack"
4
+ require "http_fn/httpie"
5
+
6
+ class HttpFn::CurlTest < Minitest::Test
7
+ include HttpFn
8
+
9
+ def setup
10
+ @curl = (verb.("GET") >>
11
+ with_path.("/coucou") >>
12
+ with_headers.(json_headers) >>
13
+ with_host.("https://api.github.com") >>
14
+ with_json.({ user: "martin" }) >>
15
+ HttpFn::Httpie.req).(empty_req)
16
+ end
17
+
18
+ def test_should_return_a_curl_command
19
+ res = <<EOF
20
+ echo $'{"user":"martin"}' |\\
21
+ http GET 'https://api.github.com/coucou?' \\
22
+ 'accept: application/json' \\
23
+ 'Content-Type: application/json' \\
24
+ 'user-agent: paw/3.0.11 (macintosh; os x/10.11.6) gcdhttprequest'
25
+ EOF
26
+ assert_equal res.chomp, @curl
27
+ end
28
+ end
@@ -0,0 +1,45 @@
1
+ require "minitest_helper"
2
+ require "rack"
3
+ require "http_fn/rack"
4
+
5
+ # https://github.com/macournoyer/thin/blob/a7d1174f47a4491a15b505407c0501cdc8d8d12c/spec/request/parser_spec.rb
6
+ # rack sample
7
+ # https://gist.github.com/a1869ea2e5db0563d5772b2eff74ff9f
8
+ class HttpFn::RackTest < MiniTest::Test
9
+ include HttpFn
10
+
11
+ def setup
12
+ @req = HttpFn.empty_req.then(&with_host.("http://localhost:3000"))
13
+ end
14
+
15
+ def test_upcase_headers
16
+ req = @req.then(&add_headers.("X-invisible" => "tata"))
17
+ env = Rack.to_env.(req)
18
+ assert_equal "tata", env["HTTP_X_INVISIBLE"]
19
+ end
20
+
21
+ def test_basic_headers
22
+ env = empty_req.then(&(verb.("get") >> with_host.("https://localhost:3000") >> with_query.({ "name" => "martin" }) >> with_path.("/users/1") >> Rack.to_env))
23
+ # assert_equal "HTTP/1.1", env["SERVER_PROTOCOL"]
24
+ # assert_equal "HTTP/1.1", env["HTTP_VERSION"]
25
+ # assert_equal "/users/1", env["REQUEST_PATH"]
26
+ assert_equal "GET", env["REQUEST_METHOD"]
27
+ assert_equal "https", env["rack.url_scheme"]
28
+ assert_equal "/users/1", env["PATH_INFO"]
29
+ end
30
+
31
+ def test_host
32
+ env = empty_req.then(&(verb.("get") >> with_host.("https://localhost:3000") >> with_query.({ "name" => "martin" }) >> with_path.("/users/1") >> Rack.to_env))
33
+ # assert_equal "localhost:3000", env["HTTP_HOST"]
34
+ assert_equal "localhost", env["SERVER_NAME"]
35
+ assert_equal 3000, env["SERVER_PORT"]
36
+ assert_equal "name=martin", env["QUERY_STRING"]
37
+ assert_equal "", env["SCRIPT_NAME"]
38
+ end
39
+
40
+ def test_dont_prepend_HTTP_to_content_type_and_content_length
41
+ env = empty_req.then(&(verb.("get") >> with_host.("https://localhost:3000") >> with_query.({ "name" => "martin" }) >> with_path.("/users/1") >> add_headers.({ "content-type" => "application/json" }) >> Rack.to_env))
42
+ assert_equal "application/json", env["CONTENT_TYPE"]
43
+ assert_equal 0, env["CONTENT_LENGTH"]
44
+ end
45
+ end
@@ -0,0 +1,13 @@
1
+ require "minitest_helper"
2
+ require "http_fn"
3
+
4
+ class HttpFn::HttpFnTest < Minitest::Test
5
+ include HttpFn
6
+
7
+ def test_basic_auth
8
+ req = with_basic_auth.("martin").("secret").(empty_req)
9
+ authorization = req[:header]["Authorization"]
10
+ refute_nil authorization
11
+ assert_equal "Basic bWFydGluOnNlY3JldA==", authorization
12
+ end
13
+ end
@@ -0,0 +1,4 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'http_fn'
3
+
4
+ require 'minitest/autorun'
@@ -0,0 +1,7 @@
1
+ require 'minitest_helper'
2
+
3
+ class TestHttpFn < MiniTest::Unit::TestCase
4
+ def test_that_it_has_a_version_number
5
+ refute_nil ::HttpFn::VERSION
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: http_fn
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Martin Chabot
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-12-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rack
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: fn_reader
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'
83
+ description: Http client that levrage the use of fp principle
84
+ email:
85
+ - chabotm@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".ruby-version"
92
+ - ".travis.yml"
93
+ - Gemfile
94
+ - LICENSE.txt
95
+ - README.md
96
+ - Rakefile
97
+ - http_fn.gemspec
98
+ - lib/http_fn.rb
99
+ - lib/http_fn/.ruby-version
100
+ - lib/http_fn/curl.rb
101
+ - lib/http_fn/http_fn.rb
102
+ - lib/http_fn/httpie.rb
103
+ - lib/http_fn/net_http.rb
104
+ - lib/http_fn/operators.rb
105
+ - lib/http_fn/rack.rb
106
+ - lib/http_fn/utils.rb
107
+ - lib/http_fn/version.rb
108
+ - test/http_fn/curl_test.rb
109
+ - test/http_fn/httpie_test.rb
110
+ - test/http_fn/rack_test.rb
111
+ - test/http_fn_test.rb
112
+ - test/minitest_helper.rb
113
+ - test/test_http_fn.rb
114
+ homepage: ''
115
+ licenses:
116
+ - MIT
117
+ metadata: {}
118
+ post_install_message:
119
+ rdoc_options: []
120
+ require_paths:
121
+ - lib
122
+ required_ruby_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ required_rubygems_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ requirements: []
133
+ rubygems_version: 3.1.4
134
+ signing_key:
135
+ specification_version: 4
136
+ summary: Http client that levrage the use of fp principle
137
+ test_files:
138
+ - test/http_fn/curl_test.rb
139
+ - test/http_fn/httpie_test.rb
140
+ - test/http_fn/rack_test.rb
141
+ - test/http_fn_test.rb
142
+ - test/minitest_helper.rb
143
+ - test/test_http_fn.rb