rom-http 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 269706f2e8c14e8374fefeab550e33d7c7d58c0d
4
+ data.tar.gz: caa9d7aa5081a6d2fe8dc74ee5b9db0d88a905d9
5
+ SHA512:
6
+ metadata.gz: aeca55f4998f9a2102add906771785036938e9f14fd463e4d3b6390497ebdec2576eefec204b22fd8722cd67f7275eff838b3328b28354b5ba9760e56584d080
7
+ data.tar.gz: d1bffe2ea11049e3845f6d9cd9873929bae8c9dd9d5e4bb0f95b33c07851d04b04a56bcd9a370d3447564a3f73f25a532a425e63d62aa8128b427fde096c321b
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ /.bundle
2
+ /.yardoc
3
+ /_yardoc
4
+ /coverage
5
+ /vendor
6
+ /doc
7
+ /pkg
8
+ /spec/reports
9
+ /tmp
10
+ Gemfile.lock
11
+ *.bundle
12
+ *.so
13
+ *.o
14
+ *.a
15
+ mkmf.log
16
+ log/*.log
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --require=spec_helper
2
+ --color
3
+ --order random
data/.rubocop.yml ADDED
@@ -0,0 +1,19 @@
1
+ # Generated by `rubocop --auto-gen-config`
2
+ inherit_from: .rubocop_todo.yml
3
+
4
+ Metrics/LineLength:
5
+ Max: 100
6
+
7
+ # No need to handle LoadError in Rakefile
8
+ Lint/HandleExceptions:
9
+ Exclude:
10
+ - Rakefile
11
+ - rakelib/rubocop.rake
12
+
13
+ # Documentation checked by Inch CI
14
+ Style/Documentation:
15
+ Enabled: false
16
+
17
+ # Allow rom-http
18
+ Style/FileName:
19
+ Enabled: false
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,6 @@
1
+ # This configuration was generated by `rubocop --auto-gen-config`
2
+ # on 2015-08-05 23:05:48 +0100 using RuboCop version 0.32.0.
3
+ # The point is for the user to remove these configuration records
4
+ # one by one as the offenses are removed from the code base.
5
+ # Note that changes in the inspected code, or installation of new
6
+ # versions of RuboCop, may require this file to be generated again.
data/.travis.yml ADDED
@@ -0,0 +1,28 @@
1
+ language: ruby
2
+ sudo: false
3
+ cache: bundler
4
+ bundler_args: --without sql benchmarks console tools
5
+ script: "bundle exec rake ci"
6
+ rvm:
7
+ - 2.0
8
+ - 2.1
9
+ - 2.2
10
+ - rbx-2
11
+ - jruby
12
+ - ruby-head
13
+ - jruby-head
14
+ env:
15
+ global:
16
+ - JRUBY_OPTS='--dev -J-Xmx1024M'
17
+ matrix:
18
+ allow_failures:
19
+ - rvm: ruby-head
20
+ - rvm: jruby-head
21
+ - rvm: rbx-2
22
+ notifications:
23
+ webhooks:
24
+ urls:
25
+ - https://webhooks.gitter.im/e/39e1225f489f38b0bd09
26
+ on_success: change
27
+ on_failure: always
28
+ on_start: false
data/Gemfile ADDED
@@ -0,0 +1,21 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem 'rom', github: 'rom-rb/rom', branch: 'master'
7
+ gem 'faraday'
8
+ gem 'inflecto'
9
+ end
10
+
11
+ group :tools do
12
+ gem 'guard'
13
+ gem 'guard-rspec'
14
+ gem 'guard-rubocop'
15
+ gem 'rubocop', '~> 0.28'
16
+
17
+ platform :mri do
18
+ gem 'mutant', '>= 0.8.0', github: 'mbj/mutant', branch: 'master'
19
+ gem 'mutant-rspec'
20
+ end
21
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Ruby Object Mapper Team
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.
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # rom-http
2
+
3
+ HTTP adapter for ROM
4
+
5
+ ### Synopsis
6
+
7
+ ```ruby
8
+ require 'json'
9
+ require 'uri'
10
+ require 'net/http'
11
+
12
+ class RequestHandler
13
+ def call(dataset)
14
+ uri = URI(dataset.uri)
15
+ uri.path = "/#{dataset.name}/#{dataset.path}"
16
+ uri.query = URI.encode_www_form(dataset.params)
17
+
18
+ http = Net::HTTP.new(uri.host, uri.port)
19
+ request_klass = Net::HTTP.const_get(ROM::Inflector.classify(dataset.request_method))
20
+
21
+ request = request_klass.new(uri.request_uri)
22
+ dataset.headers.each_with_object(request) do |(header, value), request|
23
+ request[header.to_s] = value
24
+ end
25
+
26
+ response = http.request(request)
27
+ end
28
+ end
29
+
30
+ class ResponseHandler
31
+ def call(response, dataset)
32
+ Array([JSON.parse(response.body)]).flatten
33
+ end
34
+ end
35
+
36
+ class Users < ROM::Relation[:http]
37
+ dataset :users
38
+
39
+ def by_id(id)
40
+ with_path(id.to_s)
41
+ end
42
+ end
43
+
44
+ rom = ROM::Environment.new
45
+ rom.setup(:http, {
46
+ uri: 'http://jsonplaceholder.typicode.com',
47
+ headers: {
48
+ Accept: 'application/json'
49
+ },
50
+ request_handler: RequestHandler.new,
51
+ response_handler: ResponseHandler.new
52
+ })
53
+ rom.register_relation(Users)
54
+
55
+ container = rom.finalize.env
56
+ container.relation(:users).by_id(1).to_a
57
+ # => GET http://jsonplaceholder.typicode.com/users/1 [ Accept: application/json ]
58
+ ```
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/gem_tasks'
3
+
4
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
5
+
6
+ require 'rspec/core'
7
+ require 'rspec/core/rake_task'
8
+
9
+ RSpec::Core::RakeTask.new(:spec)
10
+ task default: [:ci]
11
+
12
+ desc 'Run CI tasks'
13
+ task ci: [:spec]
14
+
15
+ begin
16
+ require 'rubocop/rake_task'
17
+
18
+ Rake::Task[:default].enhance [:rubocop]
19
+
20
+ RuboCop::RakeTask.new do |task|
21
+ task.options << '--display-cop-names'
22
+ end
23
+ rescue LoadError
24
+ end
data/lib/rom-http.rb ADDED
@@ -0,0 +1 @@
1
+ require 'rom/http'
data/lib/rom/http.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'rom'
2
+ require 'rom/http/error'
3
+ require 'rom/http/commands'
4
+ require 'rom/http/gateway'
5
+ require 'rom/http/relation'
6
+ require 'rom/http/version'
7
+
8
+ ROM.register_adapter(:http, ROM::HTTP)
@@ -0,0 +1,4 @@
1
+ require 'rom/commands'
2
+ require 'rom/http/commands/create'
3
+ require 'rom/http/commands/update'
4
+ require 'rom/http/commands/delete'
@@ -0,0 +1,17 @@
1
+ module ROM
2
+ module HTTP
3
+ module Commands
4
+ class Create < ROM::Commands::Create
5
+ adapter :http
6
+
7
+ def execute(tuples)
8
+ Array([tuples]).flatten.map do |tuple|
9
+ attributes = input[tuple]
10
+ validator.call(attributes)
11
+ relation.insert(attributes.to_h)
12
+ end.to_a
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module ROM
2
+ module HTTP
3
+ module Commands
4
+ class Delete < ROM::Commands::Delete
5
+ adapter :http
6
+
7
+ def execute
8
+ relation.delete
9
+ end
10
+
11
+ def assert_tuple_count
12
+ # noop
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ module ROM
2
+ module HTTP
3
+ module Commands
4
+ class Update < ROM::Commands::Update
5
+ adapter :http
6
+
7
+ def execute(tuples)
8
+ Array([tuples]).flatten.map do |tuple|
9
+ attributes = input[tuple]
10
+ validator.call(attributes)
11
+ relation.update(attributes.to_h)
12
+ end.to_a
13
+ end
14
+
15
+ def assert_tuple_count
16
+ # noop
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,114 @@
1
+ module ROM
2
+ module HTTP
3
+ class Dataset
4
+ include Enumerable
5
+ include Equalizer.new(:config, :options)
6
+
7
+ attr_reader :config, :options
8
+
9
+ def initialize(config, options = {})
10
+ @config = config
11
+ @options = {
12
+ request_method: :get,
13
+ path: '',
14
+ params: {}
15
+ }.merge(options)
16
+ end
17
+
18
+ def uri
19
+ config[:uri]
20
+ end
21
+
22
+ def headers
23
+ config.fetch(:headers, {}).merge(options.fetch(:headers, {}))
24
+ end
25
+
26
+ def name
27
+ config[:name].to_s
28
+ end
29
+
30
+ def path
31
+ options[:path].to_s.sub(%r{\A/}, '')
32
+ end
33
+
34
+ def absolute_path
35
+ '/' + path
36
+ end
37
+
38
+ def request_method
39
+ options[:request_method]
40
+ end
41
+
42
+ def params
43
+ options[:params]
44
+ end
45
+
46
+ def with_headers(headers)
47
+ self.class.new(config, options.merge(headers: headers))
48
+ end
49
+
50
+ def add_header(header, value)
51
+ with_headers(headers.merge(header => value))
52
+ end
53
+
54
+ def with_options(opts)
55
+ self.class.new(config, options.merge(opts))
56
+ end
57
+
58
+ def with_path(path)
59
+ with_options(path: path)
60
+ end
61
+
62
+ def append_path(path)
63
+ with_options(path: options[:path] + '/' + path)
64
+ end
65
+
66
+ def with_request_method(request_method)
67
+ with_options(request_method: request_method)
68
+ end
69
+
70
+ def with_params(params)
71
+ with_options(params: params)
72
+ end
73
+
74
+ def each(&block)
75
+ return to_enum unless block_given?
76
+ response.each(&block)
77
+ end
78
+
79
+ def insert(params)
80
+ with_options(
81
+ request_method: :post,
82
+ params: params
83
+ ).response
84
+ end
85
+
86
+ def update(params)
87
+ with_options(
88
+ request_method: :put,
89
+ params: params
90
+ ).response
91
+ end
92
+
93
+ def delete
94
+ with_options(
95
+ request_method: :delete
96
+ ).response
97
+ end
98
+
99
+ def response
100
+ response_handler.call(request_handler.call(self), self)
101
+ end
102
+
103
+ private
104
+
105
+ def response_handler
106
+ config[:response_handler]
107
+ end
108
+
109
+ def request_handler
110
+ config[:request_handler]
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,17 @@
1
+ module ROM
2
+ module HTTP
3
+ Error = Class.new(StandardError)
4
+
5
+ class GatewayConfigurationError < Error
6
+ def initialize(missing_keys)
7
+ if missing_keys.length > 1
8
+ msg = "Missing #{missing_keys[0..-1].join(', ')} and #{missing_keys.last}"
9
+ else
10
+ msg = "Missing #{missing_keys.last}"
11
+ end
12
+
13
+ super(msg + ' in ROM::HTTP::Gateway configuration')
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,31 @@
1
+ require 'thread_safe'
2
+ require 'rom/http/dataset'
3
+
4
+ module ROM
5
+ module HTTP
6
+ class Gateway < ROM::Gateway
7
+ attr_reader :datasets, :config
8
+ private :datasets, :config
9
+
10
+ def initialize(config)
11
+ missing_keys = [:uri, :request_handler, :response_handler] - config.keys
12
+ fail GatewayConfigurationError, missing_keys unless missing_keys.empty?
13
+
14
+ @datasets = ThreadSafe::Cache.new
15
+ @config = config
16
+ end
17
+
18
+ def [](name)
19
+ datasets.fetch(name)
20
+ end
21
+
22
+ def dataset(name)
23
+ datasets[name] = Dataset.new(config.merge(name: name))
24
+ end
25
+
26
+ def dataset?(name)
27
+ datasets.key?(name)
28
+ end
29
+ end
30
+ end
31
+ end