absperf-dm-ssbe-adapter 0.10.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,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Paul Sadauskas
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,6 @@
1
+
2
+ # dm-ssbe-adapter
3
+
4
+ A DataMapper Adapter for the System Shepherd flavor of ReST Web Services.
5
+
6
+
@@ -0,0 +1,67 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "dm-ssbe-adapter"
8
+ gem.summary = %Q{A DataMapper adapter for System Shepherd flavored REST services}
9
+ gem.email = "psadauskas@gmail.com"
10
+ gem.homepage = "http://github.com/absperf/dm-ssbe-adapter"
11
+ gem.authors = ["Paul Sadauskas"]
12
+
13
+ gem.add_dependency 'dm-core', '~> 0.10.0'
14
+ gem.add_dependency 'resourceful', '~> 0.5.0'
15
+ gem.add_dependency 'extlib', '~> 0.9.11'
16
+ gem.add_dependency 'json', '~> 1.1.0'
17
+
18
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
19
+ end
20
+ rescue LoadError
21
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
22
+ end
23
+
24
+ begin
25
+ require 'spec/rake/spectask'
26
+ Spec::Rake::SpecTask.new('spec') do |t|
27
+ t.spec_opts << '--options spec/spec.opts' if File.exists?('spec/spec.opts')
28
+ t.libs << 'lib'
29
+ t.spec_files = FileList["spec/**/*_spec.rb"]
30
+ end
31
+ rescue LoadError
32
+ task :spec do
33
+ abort 'rspec is not available'
34
+ end
35
+ end
36
+
37
+ begin
38
+ require 'rcov/rcovtask'
39
+ Rcov::RcovTask.new do |test|
40
+ test.libs << 'test'
41
+ test.pattern = 'test/**/*_test.rb'
42
+ test.verbose = true
43
+ end
44
+ rescue LoadError
45
+ task :rcov do
46
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
47
+ end
48
+ end
49
+
50
+
51
+ task :default => :spec
52
+
53
+ require 'rake/rdoctask'
54
+ Rake::RDocTask.new do |rdoc|
55
+ if File.exist?('VERSION.yml')
56
+ config = YAML.load(File.read('VERSION.yml'))
57
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
58
+ else
59
+ version = ""
60
+ end
61
+
62
+ rdoc.rdoc_dir = 'rdoc'
63
+ rdoc.title = "dm-ssbe-adapter #{version}"
64
+ rdoc.rdoc_files.include('README*')
65
+ rdoc.rdoc_files.include('lib/**/*.rb')
66
+ end
67
+
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 10
3
+ :patch: 0
4
+ :major: 0
@@ -0,0 +1,70 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{dm-ssbe-adapter}
5
+ s.version = "0.10.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Paul Sadauskas"]
9
+ s.date = %q{2009-06-10}
10
+ s.email = %q{psadauskas@gmail.com}
11
+ s.extra_rdoc_files = [
12
+ "LICENSE",
13
+ "README.mkd"
14
+ ]
15
+ s.files = [
16
+ ".document",
17
+ ".gitignore",
18
+ "LICENSE",
19
+ "README.mkd",
20
+ "Rakefile",
21
+ "VERSION.yml",
22
+ "dm-ssbe-adapter.gemspec",
23
+ "example.rb",
24
+ "lib/dm-ssbe-adapter.rb",
25
+ "lib/dm-ssbe-adapter/model_extensions.rb",
26
+ "lib/dm-ssbe-adapter/service.rb",
27
+ "lib/dm-ssbe-adapter/ssbe_authenticator.rb",
28
+ "lib/dm-types/href.rb",
29
+ "spec/create_spec.rb",
30
+ "spec/models.rb",
31
+ "spec/reading_spec.rb",
32
+ "spec/simple_sinatra_server.rb",
33
+ "spec/spec.opts",
34
+ "spec/spec_helper.rb"
35
+ ]
36
+ s.homepage = %q{http://github.com/absperf/dm-ssbe-adapter}
37
+ s.rdoc_options = ["--charset=UTF-8"]
38
+ s.require_paths = ["lib"]
39
+ s.rubygems_version = %q{1.3.3}
40
+ s.summary = %q{A DataMapper adapter for System Shepherd flavored REST services}
41
+ s.test_files = [
42
+ "spec/simple_sinatra_server.rb",
43
+ "spec/reading_spec.rb",
44
+ "spec/spec_helper.rb",
45
+ "spec/create_spec.rb",
46
+ "spec/models.rb"
47
+ ]
48
+
49
+ if s.respond_to? :specification_version then
50
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
51
+ s.specification_version = 3
52
+
53
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
54
+ s.add_runtime_dependency(%q<dm-core>, ["~> 0.10.0"])
55
+ s.add_runtime_dependency(%q<resourceful>, ["~> 0.5.0"])
56
+ s.add_runtime_dependency(%q<extlib>, ["~> 0.9.11"])
57
+ s.add_runtime_dependency(%q<json>, ["~> 1.1.0"])
58
+ else
59
+ s.add_dependency(%q<dm-core>, ["~> 0.10.0"])
60
+ s.add_dependency(%q<resourceful>, ["~> 0.5.0"])
61
+ s.add_dependency(%q<extlib>, ["~> 0.9.11"])
62
+ s.add_dependency(%q<json>, ["~> 1.1.0"])
63
+ end
64
+ else
65
+ s.add_dependency(%q<dm-core>, ["~> 0.10.0"])
66
+ s.add_dependency(%q<resourceful>, ["~> 0.5.0"])
67
+ s.add_dependency(%q<extlib>, ["~> 0.9.11"])
68
+ s.add_dependency(%q<json>, ["~> 1.1.0"])
69
+ end
70
+ end
@@ -0,0 +1,31 @@
1
+
2
+ require 'rubygems'
3
+ require 'resourceful'
4
+ require 'dm-core'
5
+ require 'lib/dm-ssbe-adapter'
6
+
7
+ DataMapper.setup(:default, :adapter => :ssbe,
8
+ :username => 'admin',
9
+ :password => 'admin',
10
+ :services_uri => 'http://auth.v6.localhost/services',
11
+ :logger => Resourceful::StdOutLogger.new)
12
+
13
+
14
+ puts "GET Service"
15
+ puts Service.get("http://auth.v6.localhost/services/AllAccounts").inspect
16
+
17
+ puts "All Services"
18
+ puts Service.all.inspect
19
+
20
+ puts "Create Service"
21
+ s = Service.create(:name => "OtherAccounts",
22
+ :resource_href => "http://auth.v6.localhost/services/AllOtherAccounts")
23
+
24
+ puts s.inspect
25
+
26
+ puts "Update Service"
27
+ s.resource_href = "http://auth.v6.localhost/services/OtherAccounts"
28
+ s.save
29
+ puts s.inspect
30
+
31
+
@@ -0,0 +1,186 @@
1
+
2
+ #require 'dm-core'
3
+ require 'resourceful'
4
+ require 'extlib'
5
+ require 'json'
6
+
7
+ __DIR__ = File.dirname(__FILE__)
8
+ require File.join(__DIR__, 'dm-ssbe-adapter', 'ssbe_authenticator')
9
+ require File.join(__DIR__, 'dm-types', 'href')
10
+ require File.join(__DIR__, 'dm-ssbe-adapter', 'service')
11
+ require File.join(__DIR__, 'dm-ssbe-adapter', 'model_extensions')
12
+
13
+ module DataMapper::Adapters
14
+
15
+ class HttpAdapter < AbstractAdapter
16
+ attr_reader :http
17
+
18
+ def initialize(name, options = {})
19
+ super
20
+
21
+ @http = Resourceful::HttpAccessor.new
22
+ @http.cache_manager = Resourceful::InMemoryCacheManager.new
23
+ @http.logger = options[:logger] || Resourceful::BitBucketLogger.new
24
+ end
25
+
26
+ def logger
27
+ http.logger
28
+ end
29
+ end
30
+
31
+ class SsbeAdapter < HttpAdapter
32
+ attr_reader :services_uri
33
+
34
+ SSJ = 'application/vnd.absperf.ssbe+json'
35
+
36
+ def initialize(name, options = {})
37
+ super
38
+
39
+ username, password = options[:username], options[:password]
40
+
41
+ http.add_authenticator(Resourceful::SSBEAuthenticator.new(username, password))
42
+
43
+ @services_uri = options[:services_uri]
44
+ end
45
+
46
+ def create(resources)
47
+ resources.each do |resource|
48
+ http_resource = collection_resource_for(resource.model)
49
+ document = serialize(resource)
50
+
51
+ response = http_resource.post(document, :content_type => SSJ)
52
+
53
+ update_attributes(resource, deserialize(response.body))
54
+ end
55
+ end
56
+
57
+ def read(query)
58
+ ## [dm-core] need an easy way to determine if we're
59
+ # looking up a single record by key
60
+ if querying_on_href?(query)
61
+ href = if query.respond_to?(:location)
62
+ query.location
63
+ else
64
+ operand = query.conditions.operands.first
65
+ operand.value
66
+ end
67
+
68
+ http_resource = http.resource(href, :accept => SSJ)
69
+ begin
70
+ response = http_resource.get
71
+ rescue Resourceful::UnsuccessfulHttpRequestError => e
72
+ if e.http_response.code == 404
73
+ return []
74
+ else
75
+ raise e
76
+ end
77
+ end
78
+ record = deserialize(response.body)
79
+ if record.has_key?(:items)
80
+ query.filter_records(record[:items])
81
+ else
82
+ [record]
83
+ end
84
+ else
85
+ resource = collection_resource_for(query)
86
+ opts = {}
87
+ opts.merge(:cache_control => 'no-cache') if query.reload?
88
+
89
+ response = resource.get(opts)
90
+
91
+ records = deserialize(response.body)
92
+ query.filter_records(records[:items])
93
+ end
94
+ end
95
+
96
+ def update(attributes, collection)
97
+ collection.each do |resource|
98
+ http_resource = http.resource(resource.href, :accept => SSJ)
99
+ response = http_resource.put(serialize(attributes), :content_type => SSJ)
100
+
101
+ update_attributes(resource, deserialize(response.body))
102
+ end
103
+ end
104
+
105
+ def delete(collection)
106
+ collection.each do |resource|
107
+ http_resource = http.resource(resource.href, :accept => SSJ)
108
+ response = http_resource.delete
109
+
110
+ update_attributes(resource, deserialize(response.body))
111
+ end
112
+ end
113
+
114
+ protected
115
+
116
+ ## [dm-core] resource.update_fields(attributes)
117
+ # updates any changed fields from a response
118
+ # eg, created_at, updated_at, etc...
119
+ def update_attributes(resource, attributes)
120
+ attributes.each do |field, value|
121
+ property = resource.model.properties.detect { |p| p.field == field }
122
+ property.set!(resource, value) if property
123
+ end
124
+ resource
125
+ end
126
+
127
+ def serialize(resource_or_attributes)
128
+ if resource_or_attributes.is_a?(DataMapper::Resource)
129
+ attributes_as_fields(resource_or_attributes.dirty_attributes)
130
+ else
131
+ attributes_as_fields(resource_or_attributes)
132
+ end.merge(:_type => resource_or_attributes.model).to_json
133
+ end
134
+
135
+ def deserialize(document)
136
+ Mash.new(JSON.parse(document))
137
+ end
138
+
139
+ def querying_on_href?(query)
140
+ return true if query.respond_to?(:location) && query.location
141
+
142
+ return false unless query.conditions.operands.size == 1
143
+
144
+ operand = query.conditions.operands.first
145
+ return false unless operand.is_a?(DataMapper::Query::Conditions::EqualToComparison)
146
+
147
+ query.model.key.first == operand.subject
148
+ end
149
+
150
+ def collection_resource_for(query_or_model)
151
+ if query_or_model.is_a?(DataMapper::Query)
152
+ query = query_or_model
153
+ model = query.model
154
+ else
155
+ model = query_or_model
156
+ end
157
+
158
+ ## [dm-core] Make it easy to add more things to a query
159
+ collection_uri = if model == Service
160
+ @services_uri
161
+ elsif query && query.respond_to?(:location)
162
+ query.location
163
+ elsif query && uri = association_collection_uri(query)
164
+ uri
165
+ else
166
+ Service[model.service_name].resource_href
167
+ end
168
+
169
+ http.resource(collection_uri, :accept => SSJ)
170
+ end
171
+
172
+ def association_collection_uri(query)
173
+ return false unless query.conditions.operands.size == 1
174
+
175
+ operand = query.conditions.operands.first
176
+ return false unless operand.is_a?(DataMapper::Query::Conditions::EqualToComparison)
177
+ return false unless operand.subject.name.to_s =~ /_href\Z/
178
+
179
+ operand.value
180
+ end
181
+
182
+ end
183
+
184
+ end
185
+
186
+
@@ -0,0 +1,105 @@
1
+
2
+ module DataMapper
3
+
4
+ module SsbeModelExtensions
5
+
6
+ def service_name(name = nil)
7
+ if name
8
+ @service_name = name
9
+ else
10
+ @service_name
11
+ end
12
+ end
13
+
14
+ def refers_to_collection_of(collection_name, options = {})
15
+ options.merge!(:min => 0, :max => n)
16
+ options[:child_repository_name] = options.delete(:repository)
17
+ options[:parent_repository_name] = repository.name
18
+
19
+ rel = CollectionReference.new(collection_name, nil, self, options)
20
+ relationships(repository.name)[collection_name] = rel
21
+ end
22
+
23
+ def refers_to(name, options = {})
24
+ options[:child_repository_name] = options.delete(:repository)
25
+ options[:parent_repository_name] = repository.name
26
+
27
+ rel = Reference.new(name, self, nil, options)
28
+ relationships(repository.name)[name] = rel
29
+ end
30
+
31
+ end
32
+
33
+ Model.send(:include, SsbeModelExtensions)
34
+
35
+ module SsbeQueryExtensions
36
+
37
+ attr_accessor :location
38
+
39
+ def initialize(repository, model, options = {})
40
+ super
41
+ @location = @options.fetch(:location, nil)
42
+ end
43
+
44
+ def assert_valid_options(options)
45
+ end
46
+
47
+ def location=(location)
48
+ @location = location
49
+ @options = @options.dup # Why do you hate freedom?
50
+ @options[:location] = location # so copy works
51
+ end
52
+
53
+ end
54
+
55
+ class CollectionReference < Associations::OneToMany::Relationship
56
+
57
+ # NOTE: This is why asserting valid options is a retarded idea. It
58
+ # makes it a giant pain in the ass to extend anything. I want a
59
+ # :location option on query. I have to have to extend every instance
60
+ # of a query, and set the location manually. The single commented line
61
+ # in `#source_scope` would be all thats needed, otherwise.
62
+ def query_for(source, other_query = nil)
63
+ query = super
64
+ query.extend(SsbeQueryExtensions)
65
+ query.location = reference_property.get(source)
66
+ query
67
+ end
68
+
69
+ def source_scope(source)
70
+ #{:location => child_key.get(source)}
71
+ {}
72
+ end
73
+
74
+ def reference_property
75
+ property_name = "#{name}_href".to_sym
76
+
77
+ parent_model.properties(parent_repository_name)[property_name]
78
+ end
79
+
80
+ end
81
+
82
+ class Reference < Associations::ManyToOne::Relationship
83
+
84
+ def query_for(source, other_query = nil)
85
+ query = super
86
+ query.extend(SsbeQueryExtensions)
87
+ query.location = reference_property.get(source)
88
+ query
89
+ end
90
+
91
+ def source_scope(source)
92
+ #{:location => child_key.get(source)}
93
+ {}
94
+ end
95
+
96
+ def reference_property
97
+ property_name = "#{name}_href".to_sym
98
+
99
+ child_model.properties(parent_repository_name)[property_name]
100
+ end
101
+
102
+ end
103
+
104
+ end
105
+
@@ -0,0 +1,33 @@
1
+
2
+ class Service
3
+ include DataMapper::Resource
4
+
5
+ def self.default_repository_name
6
+ :ssbe
7
+ end
8
+
9
+ property :href, Href, :key => true, :serial => true
10
+ property :name, String, :nullable => false
11
+ property :resource_href, Href, :nullable => false
12
+
13
+ property :created_at, DateTime
14
+ property :updated_at, DateTime
15
+
16
+ def self.[](name)
17
+ first(:name => name.to_s)
18
+ end
19
+
20
+ def self.register(name, resource_href)
21
+ if service = self.first(:name => name)
22
+ service.href = href
23
+ service.save
24
+ else
25
+ service = self.create(:name => name.to_s,
26
+ :resource_href => href.to_s)
27
+ end
28
+
29
+ service
30
+ end
31
+
32
+
33
+ end
@@ -0,0 +1,50 @@
1
+ module Resourceful
2
+
3
+ class SSBEAuthenticator
4
+ require 'httpauth'
5
+ require 'addressable/uri'
6
+
7
+
8
+ attr_reader :username, :password, :realm, :domain, :challenge
9
+
10
+ def initialize(username, password)
11
+ @username, @password = username, password
12
+ @realm = 'SystemShepherd'
13
+ @domain = nil
14
+ end
15
+
16
+ def update_credentials(challenge_response)
17
+ @domain = Addressable::URI.parse(challenge_response.uri).host
18
+ @challenge = HTTPAuth::Digest::Challenge.from_header(challenge_response.header['WWW-Authenticate'].first)
19
+ end
20
+
21
+ def valid_for?(challenge_response)
22
+ return false unless challenge_header = challenge_response.header['WWW-Authenticate']
23
+ begin
24
+ challenge = HTTPAuth::Digest::Challenge.from_header(challenge_header.first)
25
+ rescue HTTPAuth::UnwellformedHeader
26
+ return false
27
+ end
28
+ challenge.realm == @realm
29
+ end
30
+
31
+ def can_handle?(request)
32
+ Addressable::URI.parse(request.uri).host == @domain
33
+ end
34
+
35
+ def add_credentials_to(request)
36
+ request.header['Authorization'] = credentials_for(request)
37
+ end
38
+
39
+ def credentials_for(request)
40
+ HTTPAuth::Digest::Credentials.from_challenge(@challenge,
41
+ :username => @username,
42
+ :password => @password,
43
+ :method => request.method.to_s.upcase,
44
+ :uri => Addressable::URI.parse(request.uri).path).to_header
45
+ end
46
+
47
+ end
48
+
49
+ end
50
+
@@ -0,0 +1,19 @@
1
+
2
+ module DataMapper::Types
3
+ class Href < DataMapper::Type
4
+ primitive String
5
+ length 255
6
+
7
+ def self.load(value, property)
8
+ value
9
+ end
10
+
11
+ def self.dump(value, property)
12
+ value
13
+ end
14
+
15
+ def self.typecast(value, property)
16
+ value
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe 'creating' do
4
+
5
+ it 'should create' do
6
+ article = Article.create(:title => "Test Create",
7
+ :text => "Here's how you create an article.")
8
+
9
+ article.published_at.should == "2009-04-29T15:53:00-06:00"
10
+ end
11
+ end
12
+
13
+
14
+
@@ -0,0 +1,35 @@
1
+ class Article
2
+ include DataMapper::Resource
3
+ def self.default_repository_name
4
+ :ssbe
5
+ end
6
+
7
+ service_name :AllArticles
8
+
9
+ property :href, String, :key => true
10
+ property :title, String
11
+ property :text, String
12
+ property :published_at, Time
13
+
14
+ property :comments_href, Href
15
+
16
+ refers_to_collection_of :comments
17
+ end
18
+
19
+ class Comment
20
+ include DataMapper::Resource
21
+ def self.default_repository_name
22
+ :ssbe
23
+ end
24
+
25
+
26
+ property :href, String, :key => true
27
+ property :author, String
28
+ property :text, String
29
+
30
+ property :article_href, Href
31
+
32
+ refers_to :article
33
+ end
34
+
35
+
@@ -0,0 +1,49 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe 'reading' do
4
+
5
+ it 'should get something by service name' do
6
+ articles = Article.all
7
+ articles.size.should == 2
8
+ end
9
+
10
+ it 'should get something by its href' do
11
+ article = Article.get('http://localhost:5050/articles/1')
12
+ article.text.should == "Something different from the index, so we can get which GET we used"
13
+ end
14
+
15
+ it 'should get a collection from a reference' do
16
+ comments = Article.first.comments
17
+
18
+ comments.size.should == 2
19
+ end
20
+
21
+ it 'should get a record from a reference' do
22
+ article = Article.get("http://localhost:5050/articles/1")
23
+ comment = Comment.get("http://localhost:5050/articles/1/comments/1")
24
+
25
+ comment.article.should == article
26
+ end
27
+
28
+ describe 'attributes' do
29
+ before do
30
+ @article = Article.get("http://localhost:5050/articles/1")
31
+ end
32
+
33
+ it 'should get a string attribute' do
34
+ @article.title.should == "First Article"
35
+ end
36
+
37
+ it 'should get an href attribute' do
38
+ @article.comments_href.should == 'http://localhost:5050/articles/1/comments'
39
+ end
40
+
41
+ it 'should get a time attribute' do
42
+ pending "dm-core needs to allow custom type parsing"
43
+ @article.published_at.should == Time.iso8601("2009-04-29T15:53:00-06:00")
44
+ end
45
+
46
+
47
+ end
48
+
49
+ end
@@ -0,0 +1,140 @@
1
+
2
+ require 'sinatra/base'
3
+
4
+ class App < Sinatra::Base
5
+
6
+ SSJ = 'application/vnd.absperf.ssbe+json'
7
+
8
+ use_in_file_templates!
9
+
10
+ before do
11
+ content_type SSJ
12
+ end
13
+
14
+ get '/services' do
15
+ erb :services
16
+ end
17
+
18
+ get '/articles' do
19
+ erb :articles
20
+ end
21
+
22
+ post '/articles' do
23
+ erb :article
24
+ end
25
+
26
+ get '/articles/:id' do
27
+ erb :article
28
+ end
29
+
30
+ get '/articles/:article_id/comments' do
31
+ erb :comments
32
+ end
33
+
34
+ get '/articles/:article_id/comments/:id' do
35
+ erb :comment
36
+ end
37
+
38
+ end
39
+
40
+ __END__
41
+
42
+ @@services
43
+ {
44
+ "href": "http://localhost:5050/services",
45
+ "item_count": 2,
46
+ "items": [
47
+ {
48
+ "_type": "Service",
49
+ "href": "http://localhost:5050/services/AllServices",
50
+ "name": "AllServices",
51
+ "resource_href": "http://localhost:5050/services",
52
+ "created_at": "2009-04-29T15:53:00-06:00",
53
+ "updated_at": "2009-04-29T15:53:00-06:00"
54
+ },
55
+ {
56
+ "_type": "Service",
57
+ "href": "http://localhost:5050/services/AllArticles",
58
+ "name": "AllArticles",
59
+ "resource_href": "http://localhost:5050/articles",
60
+ "created_at": "2009-04-29T15:53:00-06:00",
61
+ "updated_at": "2009-04-29T15:53:00-06:00"
62
+ }
63
+ ]
64
+ }
65
+
66
+ @@articles
67
+ {
68
+ "href": "http://localhost:5050/articles",
69
+ "item_count": 2,
70
+ "items": [
71
+ {
72
+ "_type": "Article",
73
+ "href": "http://localhost:5050/articles/1",
74
+ "title": "First Article",
75
+ "text": "This is the first article",
76
+ "comments_href": "http://localhost:5050/articles/1/comments",
77
+ "published_at": "2009-04-29T15:53:00-06:00",
78
+ "updated_at": "2009-04-29T15:53:00-06:00"
79
+ },
80
+ {
81
+ "_type": "Article",
82
+ "href": "http://localhost:5050/articles/2",
83
+ "title": "Second Article",
84
+ "text": "This is the second article",
85
+ "comments_href": "http://localhost:5050/articles/2/comments",
86
+ "published_at": "2009-04-29T15:53:00-06:00",
87
+ "updated_at": "2009-04-29T15:53:00-06:00"
88
+ }
89
+ ]
90
+ }
91
+
92
+ @@article
93
+ {
94
+ "_type": "Article",
95
+ "href": "http://localhost:5050/articles/<%= params[:id] %>",
96
+ "title": "First Article",
97
+ "text": "Something different from the index, so we can get which GET we used",
98
+ "comments_href": "http://localhost:5050/articles/<%= params[:id] %>/comments",
99
+ "published_at": "2009-04-29T15:53:00-06:00",
100
+ "updated_at": "2009-04-29T15:53:00-06:00"
101
+ }
102
+
103
+ @@comments
104
+ {
105
+ "href": "http://localhost:5050/articles/<%= params[:article_id] %>/comments",
106
+ "item_count": 2,
107
+ "items": [
108
+ {
109
+ "_type": "Comment",
110
+ "href": "http://localhost:5050/articles/<%= params[:article_id] %>/comments/1",
111
+ "author": "Paul",
112
+ "text": "This is the first comment on article <%= params[:article_id] %>",
113
+ "article_href": "http://localhost:5050/articles/<%= params[:article_id] %>",
114
+ "created_at": "2009-04-29T15:53:00-06:00",
115
+ "updated_at": "2009-04-29T15:53:00-06:00"
116
+ },
117
+ {
118
+ "_type": "Comment",
119
+ "href": "http://localhost:5050/articles/<%= params[:article_id] %>/comments/2",
120
+ "author": "Erik",
121
+ "text": "This is the second comment on article <%= params[:article_id] %>",
122
+ "article_href": "http://localhost:5050/articles/<%= params[:article_id] %>",
123
+ "created_at": "2009-04-29T15:53:00-06:00",
124
+ "updated_at": "2009-04-29T15:53:00-06:00"
125
+ }
126
+ ]
127
+ }
128
+
129
+ @@comment
130
+ {
131
+ "_type": "Comment",
132
+ "href": "http://localhost:5050/articles/<%= params[:article_id] %>/comments/<%= params[:id] %>",
133
+ "author": "Erik",
134
+ "text": "This is the second comment on article <%= params[:article_id] %>",
135
+ "article_href": "http://localhost:5050/articles/<%= params[:article_id] %>",
136
+ "created_at": "2009-04-29T15:53:00-06:00",
137
+ "updated_at": "2009-04-29T15:53:00-06:00"
138
+ }
139
+
140
+
@@ -0,0 +1,3 @@
1
+ --color
2
+ --loadby random
3
+ --format progress
@@ -0,0 +1,34 @@
1
+
2
+ require 'rubygems'
3
+ require 'thin'
4
+ require 'pp'
5
+
6
+ require '../../dm-core/lib/dm-core'
7
+
8
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
9
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
10
+ require 'dm-ssbe-adapter'
11
+ require 'dm-ssbe-adapter/model_extensions'
12
+
13
+ DataMapper.setup(:ssbe, :adapter => :ssbe,
14
+ :username => 'admin',
15
+ :password => 'admin',
16
+ :services_uri => 'http://localhost:5050/services',
17
+ #:logger => Resourceful::StdOutLogger.new)
18
+ :logger => Resourceful::BitBucketLogger.new)
19
+
20
+ require 'models'
21
+ require 'simple_sinatra_server'
22
+
23
+ @server = Thread.new do
24
+
25
+ Thin::Server.start('0.0.0.0', 5050, App, :debug => false)
26
+
27
+ end unless @server
28
+
29
+ at_exit { @server.exit }
30
+
31
+ # Give the app a change to initialize
32
+ $stderr.puts "Waiting for thin to initialize..."
33
+ sleep 0.2
34
+
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: absperf-dm-ssbe-adapter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.10.0
5
+ platform: ruby
6
+ authors:
7
+ - Paul Sadauskas
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-06-10 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: dm-core
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: 0.10.0
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: resourceful
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 0.5.0
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: extlib
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 0.9.11
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: json
47
+ type: :runtime
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 1.1.0
54
+ version:
55
+ description:
56
+ email: psadauskas@gmail.com
57
+ executables: []
58
+
59
+ extensions: []
60
+
61
+ extra_rdoc_files:
62
+ - LICENSE
63
+ - README.mkd
64
+ files:
65
+ - .document
66
+ - .gitignore
67
+ - LICENSE
68
+ - README.mkd
69
+ - Rakefile
70
+ - VERSION.yml
71
+ - dm-ssbe-adapter.gemspec
72
+ - example.rb
73
+ - lib/dm-ssbe-adapter.rb
74
+ - lib/dm-ssbe-adapter/model_extensions.rb
75
+ - lib/dm-ssbe-adapter/service.rb
76
+ - lib/dm-ssbe-adapter/ssbe_authenticator.rb
77
+ - lib/dm-types/href.rb
78
+ - spec/create_spec.rb
79
+ - spec/models.rb
80
+ - spec/reading_spec.rb
81
+ - spec/simple_sinatra_server.rb
82
+ - spec/spec.opts
83
+ - spec/spec_helper.rb
84
+ has_rdoc: false
85
+ homepage: http://github.com/absperf/dm-ssbe-adapter
86
+ post_install_message:
87
+ rdoc_options:
88
+ - --charset=UTF-8
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: "0"
96
+ version:
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: "0"
102
+ version:
103
+ requirements: []
104
+
105
+ rubyforge_project:
106
+ rubygems_version: 1.2.0
107
+ signing_key:
108
+ specification_version: 3
109
+ summary: A DataMapper adapter for System Shepherd flavored REST services
110
+ test_files:
111
+ - spec/simple_sinatra_server.rb
112
+ - spec/reading_spec.rb
113
+ - spec/spec_helper.rb
114
+ - spec/create_spec.rb
115
+ - spec/models.rb