dms 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 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