athena_resource 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 +5 -0
- data/.rspec +2 -0
- data/Gemfile +3 -0
- data/Rakefile +1 -0
- data/athena_resource.gemspec +20 -0
- data/lib/athena_resource.rb +16 -0
- data/lib/athena_resource/auth_type.rb +15 -0
- data/lib/athena_resource/base.rb +22 -0
- data/lib/athena_resource/callbacks.rb +26 -0
- data/lib/athena_resource/encoding.rb +23 -0
- data/lib/athena_resource/finders.rb +42 -0
- data/lib/athena_resource/formats.rb +16 -0
- data/lib/athena_resource/formats/athena_format.rb +90 -0
- data/lib/athena_resource/headers.rb +17 -0
- data/lib/athena_resource/version.rb +3 -0
- data/spec/athena_resource/auth_type_spec.rb +17 -0
- data/spec/athena_resource/callbacks_spec.rb +67 -0
- data/spec/athena_resource/headers_spec.rb +25 -0
- data/spec/spec_helper.rb +6 -0
- metadata +86 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "athena_resource/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "athena_resource"
|
7
|
+
s.version = AthenaResource::VERSION
|
8
|
+
s.authors = ["Micah Frost"]
|
9
|
+
s.email = ["athena@fracturedatlas.org"]
|
10
|
+
s.homepage = "http://athena.fracturedatlas.org"
|
11
|
+
s.summary = %q{ ATHENA API Wrapper}
|
12
|
+
s.description = %q{ Easily consume ATHENA resources by subclasses AthenaResource }
|
13
|
+
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
|
19
|
+
s.add_development_dependency "rspec"
|
20
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'active_resource'
|
3
|
+
|
4
|
+
require "athena_resource/version"
|
5
|
+
|
6
|
+
module AthenaResource
|
7
|
+
include ActiveResource
|
8
|
+
|
9
|
+
extend ActiveSupport::Autoload
|
10
|
+
autoload :Base
|
11
|
+
autoload :Encoding
|
12
|
+
autoload :Headers
|
13
|
+
autoload :AuthType
|
14
|
+
autoload :Callbacks
|
15
|
+
autoload :Finders
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module AthenaResource
|
2
|
+
module AuthType
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
def auth_type
|
7
|
+
if defined?(@auth_type)
|
8
|
+
@auth_type
|
9
|
+
elsif superclass != Object && superclass.auth_type
|
10
|
+
superclass.auth_type
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'athena_resource/formats'
|
2
|
+
|
3
|
+
module AthenaResource
|
4
|
+
class Base < ActiveResource::Base
|
5
|
+
self.user = AthenaResource::USER
|
6
|
+
self.password = AthenaResource::PASSWORD
|
7
|
+
self.auth_type = AthenaResource::AUTH_TYPE
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def patch(records, attributes)
|
11
|
+
response = connection.put(self.site.path + self.collection_name + "/patch/#{records.collect(&:id).join(",")}", attributes.to_json, self.headers)
|
12
|
+
format.decode(response.body).map{ |attributes| new(attributes) }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
include Encoding
|
17
|
+
include AuthType
|
18
|
+
include Headers
|
19
|
+
include Callbacks
|
20
|
+
include Finders
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module AthenaResource
|
2
|
+
module Callbacks
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
# Enable ActiveModel callbacks for models
|
7
|
+
extend ActiveModel::Callbacks
|
8
|
+
define_model_callbacks :save, :validation
|
9
|
+
end
|
10
|
+
|
11
|
+
module InstanceMethods
|
12
|
+
def save
|
13
|
+
run_callbacks :save do
|
14
|
+
super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Note, that for the time being, validation callbacks are called after before_save, and before after_save
|
19
|
+
def valid?
|
20
|
+
run_callbacks :validation do
|
21
|
+
super
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module AthenaResource
|
2
|
+
module Encoding
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
module ClassMethods
|
5
|
+
def format
|
6
|
+
read_inheritable_attribute(:format) || AthenaResource::Formats::AthenaFormat
|
7
|
+
end
|
8
|
+
|
9
|
+
def parameterize(params = {})
|
10
|
+
Hash[params.collect{|key, value| [key.camelize(:lower),value] }]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module InstanceMethods
|
15
|
+
def encode(options = {})
|
16
|
+
attrs = options.delete(:attributes) || attributes
|
17
|
+
return self.class.format.encode(attrs, options) if self.class.format.respond_to? :encode
|
18
|
+
super(options)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module AthenaResource
|
2
|
+
module Finders
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
def search_index(search_query, organization, limit=10)
|
7
|
+
if search_query.blank?
|
8
|
+
search_query = ''
|
9
|
+
else
|
10
|
+
search_query.concat(' AND ')
|
11
|
+
end
|
12
|
+
|
13
|
+
search_query.concat("organizationId:").concat("#{organization.id}")
|
14
|
+
find(:all, :params => { '_q' => search_query, '_limit' => limit})
|
15
|
+
end
|
16
|
+
|
17
|
+
#Can be used when searching for a range because you can't dupe keys in a hash
|
18
|
+
#For example: datetime=lt2011-03-02&datetime=gt2010-05-05
|
19
|
+
def query(query_str)
|
20
|
+
|
21
|
+
#Neither CGI::Escape nor URI.escape worked here
|
22
|
+
#CGI::escape escaped everything and ATHENA threw 400
|
23
|
+
#URI.escape failed to change the + to %2B which is really the only thing I wanted it to do
|
24
|
+
query_str.gsub!(/\+/,'%2B')
|
25
|
+
|
26
|
+
connection.get(self.collection_path + "?" + query_str, self.headers)
|
27
|
+
end
|
28
|
+
|
29
|
+
# This method will translate find_by_some_object_id into ...?someObjectId=9
|
30
|
+
def method_missing(method_id, *arguments)
|
31
|
+
if method_id.to_s =~ /find_by_(\w+)/
|
32
|
+
arg = arguments[0]
|
33
|
+
term = $1.camelcase(:lower)
|
34
|
+
|
35
|
+
find(:all, :params => { term => arg })
|
36
|
+
else
|
37
|
+
super
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ActiveResource
|
2
|
+
module Formats
|
3
|
+
autoload :XmlFormat, 'active_resource/formats/xml_format'
|
4
|
+
autoload :JsonFormat, 'active_resource/formats/json_format'
|
5
|
+
autoload :AthenaFormat, 'athena_resource/formats/athena_format'
|
6
|
+
|
7
|
+
# Lookup the format class from a mime type reference symbol. Example:
|
8
|
+
#
|
9
|
+
# ActiveResource::Formats[:xml] # => ActiveResource::Formats::XmlFormat
|
10
|
+
# ActiveResource::Formats[:json] # => ActiveResource::Formats::JsonFormat
|
11
|
+
def self.[](mime_type_reference)
|
12
|
+
ActiveResource::Formats.const_get(ActiveSupport::Inflector.camelize(mime_type_reference.to_s) + "Format")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'active_support/json'
|
2
|
+
|
3
|
+
module ActiveResource
|
4
|
+
module Formats
|
5
|
+
module AthenaFormat
|
6
|
+
extend self
|
7
|
+
|
8
|
+
def extension
|
9
|
+
"json"
|
10
|
+
end
|
11
|
+
|
12
|
+
def mime_type
|
13
|
+
"application/json"
|
14
|
+
end
|
15
|
+
|
16
|
+
def encode(hash, options = {})
|
17
|
+
rejections = options.delete :rejections || []
|
18
|
+
hash = hash.reject { | k , v | rejections.include? k } unless rejections.nil?
|
19
|
+
|
20
|
+
results = encode_athena(hash)
|
21
|
+
results = ActiveSupport::JSON.encode(results, options) unless options.delete(:skip_serialization)
|
22
|
+
|
23
|
+
results
|
24
|
+
end
|
25
|
+
|
26
|
+
def decode(json)
|
27
|
+
decode_athena(ActiveSupport::JSON.decode(json))
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
def decode_athena(payload)
|
32
|
+
if payload.is_a? Array
|
33
|
+
payload.collect { |element| underscore_keys(element) }
|
34
|
+
else
|
35
|
+
underscore_keys(payload)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def underscore_keys(payload)
|
40
|
+
if payload.is_a? Hash
|
41
|
+
underscored_payload = {}
|
42
|
+
payload.each do |key, value|
|
43
|
+
if value.kind_of? Hash
|
44
|
+
underscored_payload[key.underscore] = underscore_keys(value)
|
45
|
+
elsif value.kind_of? Array
|
46
|
+
underscored_payload[key.underscore] = value.collect { |v| underscore_keys(v) }
|
47
|
+
else
|
48
|
+
underscored_payload[key.underscore] = value
|
49
|
+
end
|
50
|
+
end
|
51
|
+
underscored_payload
|
52
|
+
else
|
53
|
+
if payload.respond_to? :attributes
|
54
|
+
underscore_keyes(payload.attributes)
|
55
|
+
else
|
56
|
+
payload
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def encode_athena(hash)
|
62
|
+
camelize_keys(hash)
|
63
|
+
end
|
64
|
+
|
65
|
+
def camelize_keys(hash_or_model)
|
66
|
+
if hash_or_model.respond_to? :encode and hash_or_model.respond_to? :attributes
|
67
|
+
return hash_or_model.encode(:skip_serialization => true)
|
68
|
+
end
|
69
|
+
|
70
|
+
if hash_or_model.is_a? Hash
|
71
|
+
camelized_hash = {}
|
72
|
+
|
73
|
+
hash_or_model.each do |key, value|
|
74
|
+
if value.kind_of? Hash
|
75
|
+
camelized_hash[key.camelize(:lower)] = camelize_keys(value)
|
76
|
+
elsif value.kind_of? Array
|
77
|
+
camelized_hash[key.camelize(:lower)] = value.collect{ |v| camelize_keys(v) }
|
78
|
+
else
|
79
|
+
camelized_hash[key.camelize(:lower)] = camelize_keys(value)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
camelized_hash
|
83
|
+
else
|
84
|
+
hash_or_model
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module AthenaResource
|
2
|
+
module Headers
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
headers["User-agent"] = AthenaResource::USER_AGENT || ""
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def headers
|
11
|
+
@headers ||= (superclass.headers.try(:dup) || {})
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Foo < AthenaResource::Base
|
4
|
+
end
|
5
|
+
|
6
|
+
class Bar < AthenaResource::Base
|
7
|
+
self.auth_type = "basic"
|
8
|
+
end
|
9
|
+
|
10
|
+
describe AthenaResource::AuthType do
|
11
|
+
describe "subclasses" do
|
12
|
+
it "allow for separate auth types per subclass" do
|
13
|
+
Foo.auth_type.should eq nil
|
14
|
+
Bar.auth_type.should eq "basic"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class CallbackResource < AthenaResource::Base
|
4
|
+
self.site = "http://localhost"
|
5
|
+
before_save :foo
|
6
|
+
after_save :bar
|
7
|
+
|
8
|
+
before_validation :baz
|
9
|
+
after_validation :bat
|
10
|
+
|
11
|
+
def history
|
12
|
+
@history ||= []
|
13
|
+
end
|
14
|
+
|
15
|
+
def foo; history << :foo; end
|
16
|
+
def bar; history << :bar; end
|
17
|
+
def baz; history << :baz; end
|
18
|
+
def bat; history << :bat; end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe AthenaResource::Callbacks do
|
22
|
+
before(:all) do
|
23
|
+
ActiveResource::HttpMock.respond_to do |mock|
|
24
|
+
mock.post "/callback_resources.json", {"Authorization"=>"Basic dGVzdGVyOnBhc3N3b3Jk", "Content-Type"=>"application/json", "User-agent"=>"TestingAgent"}, ""
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#save callbacks" do
|
29
|
+
subject { CallbackResource.new }
|
30
|
+
|
31
|
+
before(:each) do
|
32
|
+
subject.save
|
33
|
+
end
|
34
|
+
|
35
|
+
it "calls before save methods before calling save" do
|
36
|
+
subject.history.first.should eq :foo
|
37
|
+
end
|
38
|
+
|
39
|
+
it "calls after save methods after calling save" do
|
40
|
+
subject.history.last.should eq :bar
|
41
|
+
end
|
42
|
+
|
43
|
+
it "calls calls each method in order" do
|
44
|
+
subject.history.should eq [ :foo, :baz, :bat, :bar ]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#save callbacks" do
|
49
|
+
subject { CallbackResource.new }
|
50
|
+
|
51
|
+
before(:each) do
|
52
|
+
subject.valid?
|
53
|
+
end
|
54
|
+
|
55
|
+
it "calls before save methods before calling save" do
|
56
|
+
subject.history.first.should eq :baz
|
57
|
+
end
|
58
|
+
|
59
|
+
it "calls after save methods after calling save" do
|
60
|
+
subject.history.last.should eq :bat
|
61
|
+
end
|
62
|
+
|
63
|
+
it "calls calls each method in order" do
|
64
|
+
subject.history.should eq [ :baz, :bat ]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Foo < AthenaResource::Base
|
4
|
+
end
|
5
|
+
|
6
|
+
class Bar < AthenaResource::Base
|
7
|
+
end
|
8
|
+
|
9
|
+
describe AthenaResource::Headers do
|
10
|
+
|
11
|
+
subject { AthenaResource::Base.new }
|
12
|
+
|
13
|
+
it "sets the default user User agent" do
|
14
|
+
subject.class.headers['User-agent'].should eq "TestingAgent"
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "subclasses" do
|
18
|
+
it "allow for separate user agents per subclass" do
|
19
|
+
Foo.headers['User-agent'] = "FooAgent"
|
20
|
+
Bar.headers['User-agent'].should eq "TestingAgent"
|
21
|
+
Bar.headers['User-agent'].should_not eq "FooAgent"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: athena_resource
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Micah Frost
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-07-29 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
prerelease: false
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
type: :development
|
25
|
+
version_requirements: *id001
|
26
|
+
description: " Easily consume ATHENA resources by subclasses AthenaResource "
|
27
|
+
email:
|
28
|
+
- athena@fracturedatlas.org
|
29
|
+
executables: []
|
30
|
+
|
31
|
+
extensions: []
|
32
|
+
|
33
|
+
extra_rdoc_files: []
|
34
|
+
|
35
|
+
files:
|
36
|
+
- .gitignore
|
37
|
+
- .rspec
|
38
|
+
- Gemfile
|
39
|
+
- Rakefile
|
40
|
+
- athena_resource.gemspec
|
41
|
+
- lib/athena_resource.rb
|
42
|
+
- lib/athena_resource/auth_type.rb
|
43
|
+
- lib/athena_resource/base.rb
|
44
|
+
- lib/athena_resource/callbacks.rb
|
45
|
+
- lib/athena_resource/encoding.rb
|
46
|
+
- lib/athena_resource/finders.rb
|
47
|
+
- lib/athena_resource/formats.rb
|
48
|
+
- lib/athena_resource/formats/athena_format.rb
|
49
|
+
- lib/athena_resource/headers.rb
|
50
|
+
- lib/athena_resource/version.rb
|
51
|
+
- spec/athena_resource/auth_type_spec.rb
|
52
|
+
- spec/athena_resource/callbacks_spec.rb
|
53
|
+
- spec/athena_resource/headers_spec.rb
|
54
|
+
- spec/spec_helper.rb
|
55
|
+
homepage: http://athena.fracturedatlas.org
|
56
|
+
licenses: []
|
57
|
+
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: "0"
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: "0"
|
75
|
+
requirements: []
|
76
|
+
|
77
|
+
rubyforge_project:
|
78
|
+
rubygems_version: 1.8.5
|
79
|
+
signing_key:
|
80
|
+
specification_version: 3
|
81
|
+
summary: ATHENA API Wrapper
|
82
|
+
test_files:
|
83
|
+
- spec/athena_resource/auth_type_spec.rb
|
84
|
+
- spec/athena_resource/callbacks_spec.rb
|
85
|
+
- spec/athena_resource/headers_spec.rb
|
86
|
+
- spec/spec_helper.rb
|