http_fn 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.
@@ -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