absperf-dm-ssbe-adapter 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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