arrest 0.0.1
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.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/README.md +1 -0
- data/Rakefile +1 -0
- data/arrest.gemspec +24 -0
- data/lib/arrest.rb +18 -0
- data/lib/arrest/abstract_resource.rb +42 -0
- data/lib/arrest/http_source.rb +62 -0
- data/lib/arrest/mem_source.rb +87 -0
- data/lib/arrest/rest_child.rb +42 -0
- data/lib/arrest/root_resource.rb +34 -0
- data/lib/arrest/version.rb +3 -0
- metadata +57 -0
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Consume a rest API in a AR like fashion
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/arrest.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "arrest/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "arrest"
|
7
|
+
s.version = Arrest::VERSION
|
8
|
+
s.authors = ["Axel Tetzlaff"]
|
9
|
+
s.email = ["axel.tetzlaff@fortytools.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Another ruby rest client}
|
12
|
+
s.description = %q{Consume a rest API in a AR like fashion}
|
13
|
+
|
14
|
+
s.rubyforge_project = "arrest"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
# s.add_runtime_dependency "rest-client"
|
24
|
+
end
|
data/lib/arrest.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require "arrest/version"
|
2
|
+
|
3
|
+
require "arrest/http_source"
|
4
|
+
require "arrest/mem_source"
|
5
|
+
require "arrest/abstract_resource"
|
6
|
+
require "arrest/root_resource"
|
7
|
+
require "arrest/rest_child"
|
8
|
+
|
9
|
+
module Arrest
|
10
|
+
|
11
|
+
class Source
|
12
|
+
|
13
|
+
cattr_accessor :source
|
14
|
+
|
15
|
+
end
|
16
|
+
Source.source= MemSource.new
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Arrest
|
2
|
+
class AbstractResource
|
3
|
+
extend ActiveModel::Naming
|
4
|
+
|
5
|
+
attr_accessor :keys
|
6
|
+
|
7
|
+
class << self
|
8
|
+
|
9
|
+
def source
|
10
|
+
Arrest::Source::source
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
def body_root response
|
15
|
+
all = JSON.parse response
|
16
|
+
all["result"]
|
17
|
+
end
|
18
|
+
|
19
|
+
def build hash
|
20
|
+
raise "override in subclass with a method, that converts the given hash to an object of the desired class"
|
21
|
+
end
|
22
|
+
|
23
|
+
def resource_name
|
24
|
+
self.name.sub(/.*:/,'').downcase.pluralize
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def save
|
29
|
+
if self.respond_to?(:id) && self.id.present?
|
30
|
+
AbstractResource::source().put self
|
31
|
+
else
|
32
|
+
AbstractResource::source().post self
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def to_hash
|
38
|
+
raise "override symmetrically to build, to create a hash representation from self"
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Arrest
|
2
|
+
class HttpSource
|
3
|
+
|
4
|
+
def initialize base
|
5
|
+
@base = base
|
6
|
+
end
|
7
|
+
|
8
|
+
def add_headers headers
|
9
|
+
puts "FOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
|
10
|
+
headers['X-SplinkUser'] = '0'
|
11
|
+
headers['Content-Type'] = 'application/json'
|
12
|
+
end
|
13
|
+
|
14
|
+
def get sub
|
15
|
+
response = self.connection().get do |req|
|
16
|
+
req.url sub
|
17
|
+
add_headers req.headers
|
18
|
+
end
|
19
|
+
response.body
|
20
|
+
end
|
21
|
+
|
22
|
+
def put rest_resource
|
23
|
+
raise "To change an object it must have an id" unless rest_resource.respond_to?(:id) && rest_resource.id.present?
|
24
|
+
hash = rest_resource.to_hash
|
25
|
+
hash.delete(:id)
|
26
|
+
hash.delete("id")
|
27
|
+
|
28
|
+
response = self.connection().put do |req|
|
29
|
+
req.url "#{rest_resource.class.path}/#{rest_resource.id}"
|
30
|
+
add_headers req.headers
|
31
|
+
req.body = hash.to_json
|
32
|
+
end
|
33
|
+
response.env[:status] == 200
|
34
|
+
end
|
35
|
+
|
36
|
+
def post rest_resource
|
37
|
+
raise "new object must have setter for id" unless rest_resource.respond_to?(:id=)
|
38
|
+
raise "new object must not have id" if rest_resource.respond_to?(:id) && rest_resource.id.present?
|
39
|
+
hash = rest_resource.to_hash
|
40
|
+
|
41
|
+
response = self.connection().post do |req|
|
42
|
+
req.url rest_resource.class.path
|
43
|
+
add_headers req.headers
|
44
|
+
req.body = hash.to_json
|
45
|
+
end
|
46
|
+
location = response.env[:response_headers][:location]
|
47
|
+
id = location.gsub(/^.*\//, '')
|
48
|
+
rest_resource.id= id
|
49
|
+
response.env[:status] == 201
|
50
|
+
end
|
51
|
+
|
52
|
+
def connection
|
53
|
+
conn = Faraday.new(:url => @base) do |builder|
|
54
|
+
builder.request :url_encoded
|
55
|
+
builder.request :json
|
56
|
+
builder.response :logger
|
57
|
+
builder.adapter :net_http
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Arrest
|
2
|
+
class MemSource
|
3
|
+
|
4
|
+
attr_accessor :data
|
5
|
+
|
6
|
+
@@data = {}
|
7
|
+
|
8
|
+
def data
|
9
|
+
@@data
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
end
|
14
|
+
|
15
|
+
def wrap content,count
|
16
|
+
"{
|
17
|
+
\"queryTime\" : \"0.01866644\",
|
18
|
+
\"resultCount\" : #{count},
|
19
|
+
\"results\" : #{content} }"
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
def get sub
|
24
|
+
idx = sub.rindex(/\/[0-9]*$/)
|
25
|
+
if idx.present?
|
26
|
+
ps = [sub[0..(idx-1)], sub[(idx+1)..sub.length]]
|
27
|
+
else
|
28
|
+
ps = [sub]
|
29
|
+
end
|
30
|
+
val = traverse @@data,ps
|
31
|
+
if val.is_a?(Hash)
|
32
|
+
wrap collection_json(val.values), val.length
|
33
|
+
elsif val.blank?
|
34
|
+
wrap "{}", 0
|
35
|
+
else
|
36
|
+
wrap val.to_hash.to_json, 1
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def collection_json values
|
41
|
+
single_jsons = values.map do |v|
|
42
|
+
v.to_hash.to_json
|
43
|
+
end
|
44
|
+
"[#{single_jsons.join(',')}]"
|
45
|
+
end
|
46
|
+
|
47
|
+
def traverse hash, keys
|
48
|
+
if keys.empty?
|
49
|
+
return hash
|
50
|
+
end
|
51
|
+
key = keys.first
|
52
|
+
if hash.blank?
|
53
|
+
nil
|
54
|
+
else
|
55
|
+
traverse hash[key.to_s],keys.drop(1)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def put rest_resource
|
61
|
+
@@data[rest_resource.resource_path()][rest_resource.id.to_s] = rest_resource
|
62
|
+
raise "To change an object it must have an id" unless rest_resource.respond_to?(:id) && rest_resource.id.present?
|
63
|
+
rest_resource
|
64
|
+
end
|
65
|
+
|
66
|
+
def post rest_resource
|
67
|
+
raise "new object must have setter for id" unless rest_resource.respond_to?(:id=)
|
68
|
+
raise "new object must not have id" if rest_resource.respond_to?(:id) && rest_resource.id.present?
|
69
|
+
if @@data[rest_resource.resource_path()].present?
|
70
|
+
last_id = @@data[rest_resource.resource_path()].values.map(&:id).sort.last
|
71
|
+
else
|
72
|
+
last_id = 42
|
73
|
+
end
|
74
|
+
if last_id.is_a?(Integer)
|
75
|
+
next_id = last_id + 1
|
76
|
+
else
|
77
|
+
next_id = "#{last_id}x"
|
78
|
+
end
|
79
|
+
rest_resource.id = next_id
|
80
|
+
unless @@data[rest_resource.resource_path()].present?
|
81
|
+
@@data[rest_resource.resource_path()] = {}
|
82
|
+
end
|
83
|
+
@@data[rest_resource.resource_path()][next_id.to_s] = rest_resource
|
84
|
+
next_id
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Arrest
|
2
|
+
class RestChild < AbstractResource
|
3
|
+
attr_accessor :parent
|
4
|
+
def initialize parent
|
5
|
+
@parent = parent
|
6
|
+
end
|
7
|
+
|
8
|
+
class << self
|
9
|
+
# class method to generate path to a child resource of aonther resource
|
10
|
+
def resource_path_for parent
|
11
|
+
"#{parent.location}/#{self.resource_name}"
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def all_for parent
|
16
|
+
body_root(source().get self.resource_path_for(parent)).map do |h|
|
17
|
+
self.build(parent, h)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def find_for parent,id
|
22
|
+
r = source().get "#{self.resource_path_for(parent)}/#{id}"
|
23
|
+
body = body_root(r)
|
24
|
+
self.build body
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
# instance method to generate path to a child resource of another resource
|
30
|
+
def resource_path
|
31
|
+
self.class.resource_path_for @parent
|
32
|
+
end
|
33
|
+
|
34
|
+
# unique url for one instance of this class
|
35
|
+
def location
|
36
|
+
"#{self.class.resource_path}/#{self.id.to_s}"
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Arrest
|
2
|
+
class RootResource < AbstractResource
|
3
|
+
|
4
|
+
class << self
|
5
|
+
|
6
|
+
def resource_path
|
7
|
+
"#{self.resource_name}"
|
8
|
+
end
|
9
|
+
|
10
|
+
def all
|
11
|
+
body_root(source().get self.resource_path).map do |h|
|
12
|
+
self.build h
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def find id
|
17
|
+
r = source().get "#{self.resource_path}/#{id}"
|
18
|
+
body = body_root(r)
|
19
|
+
self.build body
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
def resource_path
|
25
|
+
"#{self.class.resource_name}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def location
|
29
|
+
self.class.resource_path + '/' + self.id.to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: arrest
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Axel Tetzlaff
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-11-03 00:00:00.000000000Z
|
13
|
+
dependencies: []
|
14
|
+
description: Consume a rest API in a AR like fashion
|
15
|
+
email:
|
16
|
+
- axel.tetzlaff@fortytools.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- .gitignore
|
22
|
+
- Gemfile
|
23
|
+
- README.md
|
24
|
+
- Rakefile
|
25
|
+
- arrest.gemspec
|
26
|
+
- lib/arrest.rb
|
27
|
+
- lib/arrest/abstract_resource.rb
|
28
|
+
- lib/arrest/http_source.rb
|
29
|
+
- lib/arrest/mem_source.rb
|
30
|
+
- lib/arrest/rest_child.rb
|
31
|
+
- lib/arrest/root_resource.rb
|
32
|
+
- lib/arrest/version.rb
|
33
|
+
homepage: ''
|
34
|
+
licenses: []
|
35
|
+
post_install_message:
|
36
|
+
rdoc_options: []
|
37
|
+
require_paths:
|
38
|
+
- lib
|
39
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
46
|
+
none: false
|
47
|
+
requirements:
|
48
|
+
- - ! '>='
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
requirements: []
|
52
|
+
rubyforge_project: arrest
|
53
|
+
rubygems_version: 1.8.10
|
54
|
+
signing_key:
|
55
|
+
specification_version: 3
|
56
|
+
summary: Another ruby rest client
|
57
|
+
test_files: []
|