pmp 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 20ab2639c7b9fadf21969f73537adca2253ff409
4
+ data.tar.gz: 2bd71ffb8dcfc812eab677e8b951070475dfcfb3
5
+ SHA512:
6
+ metadata.gz: 6ade468f61ff12b0a71bb8479c4145a750f6680fec62dac610f64e763923afd2d81417a60e0b5e274c127113b4da0c1e786cc86c1fac9ec153ba79368229d472
7
+ data.tar.gz: 5be84ad2ec152d24da4a8d9968752a43b59380faf8e0392beb0cf747d6a09328ec5c8b27f8062fcbb3f3825af697c264f1789c1005fba12f829856a3978e16bc
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.0.0-p247
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pmp.gemspec
4
+ gemspec
5
+
data/Guardfile ADDED
@@ -0,0 +1,20 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'bundler' do
5
+ watch('Gemfile')
6
+ # Uncomment next line if Gemfile contain `gemspec' command
7
+ watch(/^.+\.gemspec/)
8
+ end
9
+
10
+ guard :minitest do
11
+ # with Minitest::Unit
12
+ watch(%r{^test/(.*)\/?test_(.*)\.rb})
13
+ watch(%r{^lib/(.*/)?([^/]+)\.rb}) { |m| "test/#{m[1]}test_#{m[2]}.rb" }
14
+ watch(%r{^test/spec_helper\.rb}) { 'test' }
15
+
16
+ # with Minitest::Spec
17
+ watch(%r{^spec/(.*)_spec\.rb})
18
+ watch(%r{^lib/pmp/(.+)\.rb}) { |m| "spec/#{m[1]}_spec.rb" }
19
+ watch(%r{^spec/spec_helper\.rb}) { 'spec' }
20
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 PRX, Andrew Kuklewicz
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,136 @@
1
+ # PMP gem
2
+
3
+ Gem to make it easier to use the PMP API, which is a hypermedia API using the collection.doc+json format.
4
+
5
+ https://github.com/publicmediaplatform/pmpdocs/wiki
6
+
7
+ Very big hat tip to the hyperresource gem: https://github.com/gamache/hyperresource
8
+
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ gem 'pmp'
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install pmp
23
+
24
+ ## Usage
25
+
26
+ You can go through the `PMP::Client` as a convenience or start with a `PMP::CollectionDocument`
27
+
28
+ ```ruby
29
+
30
+ # so you need a few things, like the endpoint, default is "https://api.pmp.io"
31
+ endpoint = "https://api-sandbox.pmp.io"
32
+
33
+ # and you need credentials, the gem doesn't help you create these (yet)
34
+ client_id = "thisisnota-real-client-id-soverysorry"
35
+ client_secret = "thisisnotarealsecreteither"
36
+
37
+ # construct the client, setting some config in there
38
+ # this will automatically get a token as there is not one set
39
+ pmp = PMP::Client.new(client_id: client_id, client_secret: client_secret, endpoint: endpoint)
40
+
41
+ # or if you have a token already
42
+ token = 'thisisnotatoken'
43
+ pmp = PMP::Client.new(oauth_token: token, endpoint: endpoint)
44
+
45
+ # or if you want to get a token
46
+ pmp = PMP::Client.new(client_id: client_id, client_secret: client_secret, endpoint: endpoint)
47
+ oauth_token = pmp.token
48
+
49
+ # get the token string out of the token response
50
+ puts oauth_token.token
51
+ > 'thisisnotatoken'
52
+
53
+ # so let's get the root doc - an PMP::CollectionDocument instance
54
+ root = pmp.root
55
+
56
+ # or we can get it without the client, since PMP::CollectionDocument defaults to root
57
+ root = PMP::CollectionDocument.new(oauth_token: token, endpoint: endpoint)
58
+
59
+ # wanna get an attribute, act like it is a ruby attribute
60
+ puts root.guid
61
+ > '04224975-e93c-4b17-9df9-96db37d318f3'
62
+
63
+ # want to get the links, you can get a list of them by the rels
64
+ puts root.links.keys.sort
65
+ > ["creator", "edit", "navigation", "query"]
66
+
67
+ # want to get the creator link?
68
+ puts root.links["creator"]
69
+ > #<PMP::Link href="https://api-sandbox.pmp.io/docs/af676335-21df-4486-ab43-e88c1b48f026">
70
+
71
+ # get the same thing as a method
72
+ puts root.creator
73
+ > #<PMP::Link href="https://api-sandbox.pmp.io/docs/af676335-21df-4486-ab43-e88c1b48f026">
74
+
75
+ # like the root doc itself, this is lazy loaded
76
+ # but ask for an attribute on there, and you'll get the doc loaded up
77
+ puts root.creator.guid
78
+
79
+ #### http get request to link href occurs, loads info about the creator
80
+ > 'af676335-21df-4486-ab43-e88c1b48f026'
81
+
82
+ ```
83
+
84
+ ## Saving and Deleting
85
+
86
+ Once you have a doc, you can save or delete it like so:
87
+
88
+ ```ruby
89
+
90
+ # create a new blank doc, will generatr a guid automatically if not present
91
+ doc = PMP::CollectionDocument.new()
92
+ doc.title = "this is an example, ok?"
93
+ doc.save
94
+
95
+ # get that guid!
96
+ guid = doc.guid
97
+
98
+ # how about the link to self
99
+ self_href = doc.self.href
100
+
101
+ # get a new doc using self, could just have used the link, this is a bad example perhaps
102
+ doc = PMP::CollectionDocument.new(href: self_href)
103
+
104
+ # update an existing attribute
105
+ doc.title = "this is another awesome example, cool?"
106
+
107
+ # can add an attribute (doesn't check schema yet)
108
+ doc.adding_an_attribute = "this will get saved as a new attribute adding-an-attribute"
109
+
110
+ # can add links (doesn't check schema yet)
111
+ doc.links['some-new-link'] = PMP::Link.new(doc, {href:'http://somenewlink.io'})
112
+ new_link = doc.some_new_link
113
+
114
+ # save changes
115
+ doc.save
116
+
117
+ # never mind, delete it
118
+ doc.delete
119
+
120
+
121
+ ```
122
+
123
+ ## To Do
124
+
125
+ Think about integrating this lovely json schema parsing project: https://github.com/google/autoparse
126
+
127
+ or this one: https://github.com/hoxworth/json-schema
128
+
129
+
130
+ ## Contributing
131
+
132
+ 1. Fork it
133
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
134
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
135
+ 4. Push to the branch (`git push origin my-new-feature`)
136
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs.push 'lib'
6
+ t.libs.push 'test'
7
+ t.test_files = FileList['spec/**/*_spec.rb']
8
+ t.verbose = true
9
+ end
10
+
11
+ task :default => :test
data/lib/pmp.rb ADDED
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'rubygems'
4
+ require 'active_support/all'
5
+
6
+ require 'pmp/version'
7
+
8
+ require 'pmp/utils'
9
+ require 'pmp/configuration'
10
+ require 'pmp/connection'
11
+ require 'pmp/response'
12
+ require 'pmp/parser'
13
+
14
+ require 'pmp/links'
15
+ require 'pmp/link'
16
+ require 'pmp/collection_document'
17
+
18
+ require 'pmp/token'
19
+ require 'pmp/client'
20
+
21
+ module PMP
22
+ end
data/lib/pmp/client.rb ADDED
@@ -0,0 +1,17 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module PMP
4
+ class Client
5
+
6
+ include Configuration
7
+
8
+ def token(opts={})
9
+ PMP::Token.new(opts).get_token
10
+ end
11
+
12
+ def root(opts={}, &block)
13
+ PMP::CollectionDocument.new(opts, &block)
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,126 @@
1
+ require 'ostruct'
2
+
3
+ module PMP
4
+
5
+ # Using OpenStruct for now - perhaps use ActiveModel? hmm...
6
+ class CollectionDocument < OpenStruct
7
+
8
+ include Configuration
9
+ include Connection
10
+ include Parser
11
+
12
+ # the href/url string to retrieve info for this resource
13
+ attr_accessor :href
14
+
15
+ # keep a ref to response obj if this resulted from one
16
+ # should this be private?
17
+ attr_accessor :response
18
+
19
+ # keep a ref to original doc from which this obj was created
20
+ # should this be private?
21
+ attr_accessor :original
22
+
23
+ # all collection docs have a version
24
+ # default is '1.0'
25
+ attr_accessor :version
26
+
27
+ # has this resource actually been loaded from remote url or json document?
28
+ attr_accessor :loaded
29
+
30
+ # private var to save links obj, to handle link additions
31
+ attr_accessor :links
32
+
33
+ # document is the original json derived doc used to create this resource
34
+ # assumption is that doc is a parsed json doc confirming to collection.doc+json
35
+ # TODO: check if this is a json string or hash, for now assume it has been mashified
36
+ def initialize(options={}, &block)
37
+ super()
38
+
39
+ self.links = PMP::Links.new(self)
40
+
41
+ self.href = options.delete(:href)
42
+
43
+ # if there is a doc to be had, pull it out
44
+ self.response = options.delete(:response)
45
+ self.original = options.delete(:document)
46
+
47
+ apply_configuration(options)
48
+
49
+ if !loaded? && !href
50
+ self.href = endpoint
51
+ end
52
+
53
+ yield(self) if block_given?
54
+ end
55
+
56
+ def attributes
57
+ HashWithIndifferentAccess.new(marshal_dump.delete_if{|k,v| links.keys.include?(k.to_s)})
58
+ end
59
+
60
+ def response=(resp)
61
+ unless (!resp || loaded?)
62
+ @response = resp
63
+ self.original = resp.body
64
+ end
65
+ end
66
+
67
+ def original=(doc)
68
+ unless (!doc || loaded?)
69
+ @original = doc
70
+ parse(@original)
71
+ self.loaded = true
72
+ end
73
+ end
74
+
75
+ def load
76
+ if !loaded?
77
+ self.response = request(:get, self.href || self.self.url)
78
+ self.loaded = true
79
+ end
80
+ end
81
+ alias_method :get, :load
82
+
83
+ def save
84
+ save_link = self.edit
85
+ raise 'Edit link does not specify saving via put' unless (save_link && save_link.hints.allow.include?('PUT'))
86
+ set_guid_if_blank
87
+ url = save_link.where(guid: self.guid).url
88
+ request(:put, url, self)
89
+ end
90
+
91
+ def delete
92
+ delete_link = self.edit
93
+ raise 'Edit link does not specify deleting' unless (delete_link && delete_link.hints.allow.include?('DELETE'))
94
+ raise 'No guid specified to delete' if self.guid.blank?
95
+
96
+ url = delete_link.where(guid: self.guid).url
97
+ request(:put, url, self)
98
+ end
99
+
100
+ def loaded?
101
+ !!self.loaded
102
+ end
103
+
104
+ # url includes any params - full url
105
+ def request(method, url, body=nil) # :nodoc:
106
+ raw = connection(options.merge({url: url})).send(method) do |request|
107
+ if [:post, :put].include?(method.to_sym) && !body.blank?
108
+ request.body = body.is_a?(String) ? body : body.to_json
109
+ end
110
+ end
111
+
112
+ # may not need this, but remember how we made this response
113
+ PMP::Response.new(raw, {method: method, url: url, body: body})
114
+ end
115
+
116
+ def set_guid_if_blank
117
+ self.guid = SecureRandom.uuid if guid.blank?
118
+ end
119
+
120
+ def method_missing(method, *args)
121
+ load if (method.to_s.last != '=') && !loaded?
122
+ super
123
+ end
124
+
125
+ end
126
+ end
@@ -0,0 +1,90 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'active_support/concern'
4
+
5
+ module PMP
6
+ module Configuration
7
+
8
+ extend ActiveSupport::Concern
9
+
10
+ VALID_OPTIONS_KEYS = [
11
+ :client_id,
12
+ :client_secret,
13
+ :oauth_token,
14
+ :adapter,
15
+ :endpoint,
16
+ :user_agent,
17
+ :debug
18
+ ].freeze
19
+
20
+ # this you need to get from pmp, not covered by this
21
+ DEFAULT_CLIENT_ID = nil
22
+ DEFAULT_CLIENT_SECRET = nil
23
+
24
+ # Adapters are whatever Faraday supports - I like excon alot, so I'm defaulting it
25
+ DEFAULT_ADAPTER = :excon
26
+
27
+ # The api endpoint for YQL
28
+ DEFAULT_ENDPOINT = 'https://api.pmp.io/'.freeze
29
+
30
+ # The value sent in the http header for 'User-Agent' if none is set
31
+ DEFAULT_USER_AGENT = "PMP Ruby Gem #{PMP::VERSION}".freeze
32
+
33
+ # debug is defaulted to the ENV['DEBUG'], see below
34
+
35
+ attr_accessor *VALID_OPTIONS_KEYS
36
+
37
+ included do
38
+
39
+ attr_accessor :options
40
+
41
+ VALID_OPTIONS_KEYS.each do |key|
42
+ define_method "#{key}=" do |arg|
43
+ self.instance_variable_set("@#{key}", arg)
44
+ self.options.merge!({:"#{key}" => arg})
45
+ end
46
+ end
47
+
48
+ end
49
+
50
+ def apply_configuration(opts={})
51
+ reset! unless @options
52
+ self.options = options.merge(opts)
53
+ VALID_OPTIONS_KEYS.each do |key|
54
+ send("#{key}=", options[key])
55
+ end
56
+ end
57
+
58
+ # Convenience method to allow for global setting of configuration options
59
+ def configure
60
+ yield self
61
+ end
62
+
63
+ # Reset configuration options to their defaults
64
+ def reset!
65
+ @options = {}
66
+ self.client_id = DEFAULT_CLIENT_ID
67
+ self.client_secret = DEFAULT_CLIENT_SECRET
68
+ self.adapter = DEFAULT_ADAPTER
69
+ self.endpoint = DEFAULT_ENDPOINT
70
+ self.user_agent = DEFAULT_USER_AGENT
71
+ self.debug = ENV['DEBUG']
72
+ self
73
+ end
74
+
75
+ def options
76
+ options = {}
77
+ VALID_OPTIONS_KEYS.each { |k| options[k] = send(k) }
78
+ options
79
+ end
80
+
81
+ module ClassMethods
82
+
83
+ def keys
84
+ VALID_OPTIONS_KEYS
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+ end