dms 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in dms.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,27 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ dms (0.0.1)
5
+ httparty (>= 0.6.1)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ addressable (2.2.2)
11
+ crack (0.1.8)
12
+ httparty (0.6.1)
13
+ crack (= 0.1.8)
14
+ rspec (1.3.1)
15
+ webmock (1.5.0)
16
+ addressable (>= 2.2.2)
17
+ crack (>= 0.1.7)
18
+
19
+ PLATFORMS
20
+ ruby
21
+
22
+ DEPENDENCIES
23
+ bundler (>= 1.0.3)
24
+ dms!
25
+ httparty (>= 0.6.1)
26
+ rspec (= 1.3.1)
27
+ webmock (= 1.5.0)
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
data/dms.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "dms/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "dms"
7
+ s.version = DMS::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Jose Fernandez"]
10
+ s.email = ["jfernandez@fourcubed.com"]
11
+ s.homepage = "http://rubygems.org/gems/dms"
12
+ s.summary = %q{Ruby Gem for the FourCubed Data Management System}
13
+ s.description = %q{Ruby Gem for the FourCubed Data Management System. Wrapper for the RESTful API}
14
+
15
+ s.rubyforge_project = "dms"
16
+
17
+ s.add_dependency("httparty", ">= 0.6.1")
18
+
19
+ s.add_development_dependency("bundler", ">= 1.0.3")
20
+ s.add_development_dependency("rspec", "1.3.1")
21
+ s.add_development_dependency("webmock", "1.5.0")
22
+
23
+ s.files = `git ls-files`.split("\n")
24
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
26
+ s.require_paths = ["lib"]
27
+ end
data/lib/dms/api.rb ADDED
@@ -0,0 +1,58 @@
1
+ module DMS
2
+ class API
3
+ include HTTParty
4
+
5
+ base_uri "http://dms.fourcubed.com"
6
+ format :xml
7
+
8
+ attr_accessor :api_token
9
+ attr_accessor :api_access_key
10
+
11
+ def initialize(api_token = nil, api_access_key = nil)
12
+ @api_token = api_token.to_s
13
+ @api_access_key = api_access_key.to_s
14
+ end
15
+
16
+ def format_extension
17
+ ".#{self.class.format.to_s}"
18
+ end
19
+
20
+ def generate_timestamp
21
+ Time.now.to_i.to_s
22
+ end
23
+
24
+ def slug_to_path(slug)
25
+ File.join("/", slug.to_s) + format_extension
26
+ end
27
+
28
+ def get(slug)
29
+ response = perform_request(slug)
30
+ if response.code == 200
31
+ DMS::Node.new(response)
32
+ elsif response.code == 401
33
+ raise AuthenticationError.new(response.body)
34
+ elsif response.code == 404
35
+ raise ResourceNotFound.new(response.body)
36
+ else
37
+ raise UnknownError.new(response.body)
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def generate_signature(request_method, path, timestamp)
44
+ data = @api_token + request_method.to_s.upcase + path + timestamp
45
+ signature = OpenSSL::HMAC.digest(OpenSSL::Digest::SHA1.new, @api_access_key, data)
46
+ Base64.encode64(signature).chomp
47
+ end
48
+
49
+ def perform_request(slug)
50
+ raise "slug can't be blank!" if slug.blank?
51
+
52
+ path = slug_to_path(slug)
53
+ timestamp = generate_timestamp
54
+ signature = generate_signature(:get, path, timestamp)
55
+ self.class.get(path, :query => { :timestamp => timestamp, :signature => signature, :api_token => @api_token })
56
+ end
57
+ end
58
+ end
data/lib/dms/node.rb ADDED
@@ -0,0 +1,17 @@
1
+ module DMS
2
+ class Node
3
+ attr_reader :name
4
+ attr_reader :type
5
+ attr_reader :text
6
+ attr_reader :html
7
+
8
+ def initialize(response)
9
+ @response = response
10
+ @name = @response.parsed_response.values.first["name"]
11
+ @type = @response.parsed_response.values.first["type"]
12
+ @text = @response.parsed_response.values.first["body"]
13
+ @html = @response.parsed_response.values.first["body"]
14
+ end
15
+ end
16
+
17
+ end
@@ -0,0 +1,3 @@
1
+ module DMS
2
+ VERSION = "0.0.1"
3
+ end
data/lib/dms.rb ADDED
@@ -0,0 +1,12 @@
1
+ module DMS
2
+ require 'httparty'
3
+ require 'openssl'
4
+ require 'base64'
5
+
6
+ autoload :API, 'dms/api'
7
+ autoload :Node, 'dms/node'
8
+
9
+ class ResourceNotFound < RuntimeError; end
10
+ class AuthenticationError < RuntimeError; end
11
+ class UnknownError < RuntimeError; end
12
+ end
data/spec/api_spec.rb ADDED
@@ -0,0 +1,150 @@
1
+ require 'spec_helper'
2
+
3
+ describe DMS::API do
4
+ let(:responses) { YAML::load(File.open(File.join(File.dirname(__FILE__), 'fixtures', 'responses.yml'))) }
5
+
6
+ before(:each) do
7
+ stub_request(:get, /dms\.fourcubed\.com/).to_return(responses[200])
8
+ @api = DMS::API.new("123456token", "123456key")
9
+ end
10
+
11
+ describe "#get" do
12
+ it "calls #perform_request once with the slug" do
13
+ slug = "documents/1-foobar"
14
+ response = mock(HTTParty::Response, :code => 200, :parsed_response => { :document => {} })
15
+ @api.should_receive(:perform_request).once.with(slug).and_return(response)
16
+ @api.get(slug)
17
+ end
18
+
19
+ context "when the response has a status code of 200" do
20
+ before(:each) do
21
+ stub_request(:get, /dms\.fourcubed\.com/).to_return(responses[200])
22
+ end
23
+
24
+ it "returns an instance of DMS::Node" do
25
+ @api.get("documents/1-foobar").should be_an_instance_of(DMS::Node)
26
+ end
27
+ end
28
+
29
+ context "when the response has a status code of 401" do
30
+ before(:each) do
31
+ stub_request(:get, /dms\.fourcubed\.com/).to_return(responses[401])
32
+ end
33
+
34
+ it "raises DMS::AuthenticationError" do
35
+ lambda { @api.get("documents/1-foobar") }.should raise_error(DMS::AuthenticationError)
36
+ end
37
+ end
38
+
39
+ context "when the response has a status code of 404" do
40
+ before(:each) do
41
+ stub_request(:get, /dms\.fourcubed\.com/).to_return(responses[404])
42
+ end
43
+
44
+ it "raises DMS::ResourceNotFound" do
45
+ lambda { @api.get("documents/1-foobar") }.should raise_error(DMS::ResourceNotFound)
46
+ end
47
+ end
48
+
49
+ context "when the response has status code of 500" do
50
+ before(:each) do
51
+ stub_request(:get, /dms\.fourcubed\.com/).to_return(responses[500])
52
+ end
53
+
54
+ it "raises DMS::UnknownError" do
55
+ lambda { @api.get("documents/1-foobar") }.should raise_error(DMS::UnknownError)
56
+ end
57
+ end
58
+ end
59
+
60
+ describe "#slug_to_path" do
61
+ it "appends #format_extension" do
62
+ @api.slug_to_path("documents/1-foobar").should match /#{@api.format_extension}$/
63
+ end
64
+
65
+ it "prepends a '/'" do
66
+ @api.slug_to_path("documents/1-foobar").should match /^\/{1}/
67
+ end
68
+
69
+ context "when slug is nil" do
70
+ it "does not raise an error" do
71
+ lambda { @api.slug_to_path(nil) }.should_not raise_error
72
+ end
73
+ end
74
+
75
+ context "when slug is blank" do
76
+ it "does not raise an error" do
77
+ lambda { @api.slug_to_path('') }.should_not raise_error
78
+ end
79
+ end
80
+
81
+ context "when slug includes a trailing '/'" do
82
+ it "does not prepend another '/'" do
83
+ @api.slug_to_path("/documents/1-foobar").should_not match /^\/{2}/
84
+ end
85
+ end
86
+ end
87
+
88
+ describe "#generate_signature" do
89
+ before(:each) do
90
+ @api.api_token = "71e49b70c5f5012dda13002332b13ba0"
91
+ @api.api_access_key = "24xPxvzEgXPa5eWW7ZTirQqVt1g3NkVil5UYLUnx"
92
+ @timestamp = "12345567890"
93
+ end
94
+
95
+ it "correctly generates the signature" do
96
+ @api.send(:generate_signature, :get, 'foo', @timestamp).should == "omfvZVlOncdqPsyLa1e5/0feDgc="
97
+ end
98
+ end
99
+
100
+ describe "#perform_request" do
101
+ it "returns an instance of HTTParty::Response" do
102
+ @api.send(:perform_request, "documents/1-foo").class == HTTParty::Response
103
+ end
104
+
105
+ it "calls DMS::API.get with the correct path generated from the slug as the first parameter" do
106
+ slug = "documents/1-foobar"
107
+ path = @api.slug_to_path(slug)
108
+
109
+ DMS::API.should_receive(:get).once.with(path, anything())
110
+ @api.send(:perform_request, slug)
111
+ end
112
+
113
+ it "calls .get with a query hash as a second parameter that includes the api_token" do
114
+ slug = "documents/1-foobar"
115
+
116
+ DMS::API.should_receive(:get).once.with(anything(), {:query => hash_including(:api_token => @api.api_token)})
117
+ @api.send(:perform_request, slug)
118
+ end
119
+
120
+ it "calls .get with a query hash as a second parameter that includes the timestamp" do
121
+ slug = "documents/1-foobar"
122
+ timestamp = "12345567890"
123
+ @api.stub(:generate_timestamp).and_return(timestamp)
124
+
125
+ DMS::API.should_receive(:get).once.with(anything(), {:query => hash_including(:timestamp => timestamp)})
126
+ @api.send(:perform_request, slug)
127
+ end
128
+
129
+ it "calls .get with a query hash as a second parameter that includes the signature" do
130
+ slug = "documents/1-foobar"
131
+ signature = "dfhdskf12109231203ssdfsflksdjfl23klddsk"
132
+ @api.stub(:generate_signature).and_return(signature)
133
+
134
+ DMS::API.should_receive(:get).once.with(anything(), { :query => hash_including(:signature => signature) })
135
+ @api.send(:perform_request, slug)
136
+ end
137
+
138
+ context "when slug is nil" do
139
+ it "raises an error" do
140
+ lambda { @api.send(:perform_request, nil) }.should raise_error("slug can't be blank!")
141
+ end
142
+ end
143
+
144
+ context "when slug is blank" do
145
+ it "raises an error" do
146
+ lambda { @api.send(:perform_request, '') }.should raise_error("slug can't be blank!")
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,62 @@
1
+ 200: |
2
+ HTTP/1.1 200 OK
3
+ Content-Type: application/xml; charset=utf-8
4
+ Transfer-Encoding: chunked
5
+ Connection: keep-alive
6
+ Status: 200
7
+ X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 2.2.10
8
+ ETag: "5c7e90c6c325b5546c28ea8f9ac510ab"
9
+ X-UA-Compatible: IE=Edge,chrome=1
10
+ X-Runtime: 0.009064
11
+ Cache-Control: max-age=0, private, must-revalidate
12
+ Server: nginx/0.6.35 + Phusion Passenger 2.2.10 (mod_rails/mod_rack)
13
+
14
+ <?xml version="1.0" encoding="UTF-8"?>
15
+ <document>
16
+ <name>Foobar</name>
17
+ <body nil="true">This is the body</body>
18
+ <id type="integer">1</id>
19
+ <type>Document</type>
20
+ </document>
21
+
22
+ 401: |
23
+ HTTP/1.1 401 Unauthorized
24
+ Content-Type: text/plain; charset=utf-8
25
+ Transfer-Encoding: chunked
26
+ Connection: keep-alive
27
+ Status: 401
28
+ X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 2.2.10
29
+ X-UA-Compatible: IE=Edge,chrome=1
30
+ X-Runtime: 0.004468
31
+ Cache-Control: no-cache
32
+ Server: nginx/0.6.35 + Phusion Passenger 2.2.10 (mod_rails/mod_rack)
33
+
34
+ Invalid Signature
35
+
36
+ 404: |
37
+ HTTP/1.1 404 Not Found
38
+ Content-Type: text/html; charset=utf-8
39
+ Transfer-Encoding: chunked
40
+ Connection: keep-alive
41
+ Status: 404
42
+ X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 2.2.10
43
+ X-UA-Compatible: IE=Edge,chrome=1
44
+ X-Runtime: 0.008075
45
+ Cache-Control: no-cache
46
+ Server: nginx/0.6.35 + Phusion Passenger 2.2.10 (mod_rails/mod_rack)
47
+
48
+ Couldn't find Document with ID: 999-Foobar
49
+
50
+ 500: |
51
+ HTTP/1.1 500 Internal Server Error
52
+ Content-Type: text/html; charset=utf-8
53
+ Transfer-Encoding: chunked
54
+ Connection: keep-alive
55
+ Status: 500
56
+ X-Powered-By: Phusion Passenger (mod_rails/mod_rack) 2.2.10
57
+ X-UA-Compatible: IE=Edge,chrome=1
58
+ X-Runtime: 0.008075
59
+ Cache-Control: no-cache
60
+ Server: nginx/0.6.35 + Phusion Passenger 2.2.10 (mod_rails/mod_rack)
61
+
62
+ Server is not responding!
data/spec/node_spec.rb ADDED
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe DMS::Node do
4
+ let(:responses) { YAML::load(File.open(File.join(File.dirname(__FILE__), 'fixtures', 'responses.yml'))) }
5
+
6
+ before(:each) do
7
+ stub_request(:get, /dms\.fourcubed\.com/).to_return(responses[200])
8
+ @api = DMS::API.new("123456token", "123456key")
9
+ end
10
+
11
+ describe "#initialize" do
12
+ context "when a valid HTTParty::Response instance is passed" do
13
+ before(:each) do
14
+ @response = @api.send(:perform_request, "documents/1-foobar")
15
+ end
16
+
17
+ it "sets the @name value correct" do
18
+ @node = DMS::Node.new(@response)
19
+ @node.name.should == "Foobar"
20
+ end
21
+
22
+ it "sets the @type value correct" do
23
+ @node = DMS::Node.new(@response)
24
+ @node.type.should == "Document"
25
+ end
26
+
27
+ it "sets the @text value correct" do
28
+ @node = DMS::Node.new(@response)
29
+ @node.text.should == "This is the body"
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+
4
+ require 'rubygems'
5
+ require 'bundler/setup'
6
+ require 'dms'
7
+ require 'spec'
8
+ require 'webmock/rspec'
9
+
10
+ Spec::Runner.configure do |config|
11
+ config.include WebMock::API
12
+ end
metadata ADDED
@@ -0,0 +1,146 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dms
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Jose Fernandez
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-11-02 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: httparty
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 5
30
+ segments:
31
+ - 0
32
+ - 6
33
+ - 1
34
+ version: 0.6.1
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: bundler
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 17
46
+ segments:
47
+ - 1
48
+ - 0
49
+ - 3
50
+ version: 1.0.3
51
+ type: :development
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: rspec
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - "="
60
+ - !ruby/object:Gem::Version
61
+ hash: 25
62
+ segments:
63
+ - 1
64
+ - 3
65
+ - 1
66
+ version: 1.3.1
67
+ type: :development
68
+ version_requirements: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ name: webmock
71
+ prerelease: false
72
+ requirement: &id004 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - "="
76
+ - !ruby/object:Gem::Version
77
+ hash: 3
78
+ segments:
79
+ - 1
80
+ - 5
81
+ - 0
82
+ version: 1.5.0
83
+ type: :development
84
+ version_requirements: *id004
85
+ description: Ruby Gem for the FourCubed Data Management System. Wrapper for the RESTful API
86
+ email:
87
+ - jfernandez@fourcubed.com
88
+ executables: []
89
+
90
+ extensions: []
91
+
92
+ extra_rdoc_files: []
93
+
94
+ files:
95
+ - .gitignore
96
+ - Gemfile
97
+ - Gemfile.lock
98
+ - Rakefile
99
+ - dms.gemspec
100
+ - lib/dms.rb
101
+ - lib/dms/api.rb
102
+ - lib/dms/node.rb
103
+ - lib/dms/version.rb
104
+ - spec/api_spec.rb
105
+ - spec/fixtures/responses.yml
106
+ - spec/node_spec.rb
107
+ - spec/spec_helper.rb
108
+ has_rdoc: true
109
+ homepage: http://rubygems.org/gems/dms
110
+ licenses: []
111
+
112
+ post_install_message:
113
+ rdoc_options: []
114
+
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ none: false
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ hash: 3
123
+ segments:
124
+ - 0
125
+ version: "0"
126
+ required_rubygems_version: !ruby/object:Gem::Requirement
127
+ none: false
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ hash: 3
132
+ segments:
133
+ - 0
134
+ version: "0"
135
+ requirements: []
136
+
137
+ rubyforge_project: dms
138
+ rubygems_version: 1.3.7
139
+ signing_key:
140
+ specification_version: 3
141
+ summary: Ruby Gem for the FourCubed Data Management System
142
+ test_files:
143
+ - spec/api_spec.rb
144
+ - spec/fixtures/responses.yml
145
+ - spec/node_spec.rb
146
+ - spec/spec_helper.rb