metamolecular-chemcaster-ruby 0.1.2

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/README.rdoc ADDED
@@ -0,0 +1,35 @@
1
+ = Chemcaster Ruby API
2
+
3
+ This is the Ruby interface for the Chemcaster[http://chemcaster.com] RESTful Web
4
+ API. It consists of basic functionality needed to create
5
+ applications using chemical structure registration, storage, imaging, and
6
+ search.
7
+
8
+ == Example Use
9
+
10
+ === Connecting to the Service
11
+
12
+ require 'lib/chemcaster'
13
+ include Chemcaster
14
+
15
+ service = Service.connect 'username', 'password'
16
+
17
+ === Loading a Registry
18
+
19
+ require 'lib/chemcaster'
20
+ include Chemcaster
21
+
22
+ service = Service.connect 'username', 'password'
23
+ registries = service.registries
24
+ registries.size # => 3
25
+ registry = registries[0]
26
+
27
+ === Creating a Registry
28
+
29
+ require 'lib/chemcaster'
30
+ include Chemcaster
31
+
32
+ service = Service.connect 'username', 'password'
33
+ registries = service.registries
34
+
35
+ registries.create :name => 'CarboBlocks, Inc.'
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ require 'spec/rake/spectask'
5
+ Spec::Rake::SpecTask.new(:spec) do |spec|
6
+ spec.libs << 'lib' << 'spec'
7
+ spec.spec_files = FileList['spec/**/*_spec.rb']
8
+ end
data/lib/chemcaster.rb ADDED
@@ -0,0 +1,15 @@
1
+ require File.dirname(__FILE__) + "/chemcaster/service"
2
+ require File.dirname(__FILE__) + '/chemcaster/service'
3
+ require File.dirname(__FILE__) + '/chemcaster/registry'
4
+ require File.dirname(__FILE__) + '/chemcaster/structure'
5
+ require File.dirname(__FILE__) + '/chemcaster/query'
6
+ require File.dirname(__FILE__) + '/chemcaster/image'
7
+ require File.dirname(__FILE__) + '/chemcaster/link'
8
+ require File.dirname(__FILE__) + '/chemcaster/index'
9
+ require File.dirname(__FILE__) + '/chemcaster/item'
10
+ require File.dirname(__FILE__) + '/chemcaster/representation'
11
+ require File.dirname(__FILE__) + '/chemcaster/media_type'
12
+ require File.dirname(__FILE__) + '/chemcaster/error'
13
+
14
+ require 'rubygems'
15
+ require 'json'
@@ -0,0 +1,36 @@
1
+ module Chemcaster
2
+ class Error < RuntimeError; end
3
+ class LinkNotDefined < Error; end
4
+ class HTTPError < Error
5
+ attr_accessor :response
6
+ def initialize response
7
+ @response = response
8
+ end
9
+
10
+ def to_s
11
+ "received response code #{@response.code} with message:\n\n#{parse_errors}"
12
+ end
13
+
14
+ protected
15
+
16
+ def parse_errors
17
+ errors = nil
18
+ message = ""
19
+ begin
20
+ errors = JSON.parse response.body
21
+ rescue
22
+ return response.body
23
+ end
24
+
25
+ errors.each do |error|
26
+ if error['field']
27
+ message << "- field '#{error['field']}' #{error['text']}\n"
28
+ else
29
+ message << "- #{error['text']}\n"
30
+ end
31
+ end
32
+
33
+ message
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,6 @@
1
+ module Chemcaster
2
+ class Image < Item
3
+ attributes :width, :height, :data
4
+ resources :imageable
5
+ end
6
+ end
@@ -0,0 +1,31 @@
1
+ require File.dirname(__FILE__) + '/../chemcaster/representation'
2
+
3
+ module Chemcaster
4
+ class Index < Representation
5
+ attr_accessor :item_links#, :items
6
+ resources :parent
7
+
8
+ def create representation_attributes
9
+ @create_link.post representation_attributes
10
+ end
11
+
12
+ def size
13
+ @item_links.size
14
+ end
15
+
16
+ def [](index)
17
+ @item_links[index].get
18
+ end
19
+
20
+ protected
21
+
22
+ def load_hash atts
23
+ super
24
+
25
+ @create_link = Link.new atts['create']
26
+ @item_links = atts['items'].inject([]) do |result, atts|
27
+ result << Link.new(atts)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,24 @@
1
+ require File.dirname(__FILE__) + '/../chemcaster/representation'
2
+
3
+ module Chemcaster
4
+ class Item < Representation
5
+ resources :index
6
+
7
+ def update representation_attributes
8
+ @update_link.put representation_attributes
9
+ end
10
+
11
+ def destroy
12
+ @destroy_link.delete
13
+ end
14
+
15
+ protected
16
+
17
+ def load_hash atts
18
+ super
19
+
20
+ @update_link = Link.new atts['update']
21
+ @destroy_link = Link.new atts['destroy']
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,89 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+
4
+ module Chemcaster
5
+ class Link
6
+ def initialize atts=nil
7
+ if atts
8
+ @uri = URI.parse(atts['uri']) if atts['uri']
9
+ @media_type = atts['media_type']
10
+ @media_class = MediaType.representation(@media_type) if @media_type
11
+ end
12
+ end
13
+
14
+ def get
15
+ do_http 'get'
16
+ end
17
+
18
+ def put attributes
19
+ do_http 'put', attributes
20
+ end
21
+
22
+ def post attributes
23
+ do_http 'post', attributes
24
+ end
25
+
26
+ def delete
27
+ do_http 'delete'
28
+ end
29
+
30
+ private
31
+
32
+ def do_http method, representation=nil
33
+ validate
34
+ request = request_for_method method, representation
35
+ response = send_request request
36
+
37
+ raise(HTTPError, response) unless response.code.to_i < 300
38
+ @media_class.new self, decode(response.body)
39
+ end
40
+
41
+ def send_request request
42
+ http = Net::HTTP.new(@uri.host, @uri.port)
43
+ http.use_ssl = (@uri.scheme == 'https')
44
+
45
+ if File.exists? Service.root_ca
46
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
47
+ http.ca_path = Service.root_ca
48
+ else
49
+ message =
50
+ "net/http couldn't locate this system's root SSL certificate files."+
51
+ "On Debian Linux systems, these files are located at /etc/ssl/certs "+
52
+ "(this library's default). For more information, see:\n\n"+
53
+ "http://codeidol.com/other/rubyckbk/Internet-Services/Making-an-HTTPS-Web-Request\n"+
54
+ "http://redcorundum.blogspot.com/2008/03/ssl-certificates-and-nethttps.html\n"+
55
+ "http://notetoself.vrensk.com/2008/09/verified-https-in-ruby\n"
56
+ raise(message)
57
+ end
58
+
59
+ http.request(request)
60
+ end
61
+
62
+ def request_for_method method, attributes=nil
63
+ request = case method
64
+ when "get" then Net::HTTP::Get.new(@uri.path)
65
+ when "put" then Net::HTTP::Put.new(@uri.path)
66
+ when "post" then Net::HTTP::Post.new(@uri.path)
67
+ when "delete" then Net::HTTP::Delete.new(@uri.path)
68
+ end
69
+
70
+ request['accept'] = @media_type
71
+ request.basic_auth Service.username, Service.password
72
+
73
+ if attributes
74
+ request.body = {MediaType.hash_key(@media_type) => attributes}.to_json
75
+ request.content_type = @media_type
76
+ end
77
+
78
+ request
79
+ end
80
+
81
+ def validate
82
+ raise LinkNotDefined unless @uri && @media_class
83
+ end
84
+
85
+ def decode response
86
+ JSON.parse response
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,27 @@
1
+ module Chemcaster
2
+ class MediaType
3
+ def self.representation name
4
+ name.match(/application\/vnd\.com\.chemcaster\.(.*)\+json/)
5
+ raise "No such media type: #{name}" unless klass = $1
6
+
7
+ begin
8
+ Object.const_get(klass)
9
+ rescue
10
+ raise "No such class: #{klass}"
11
+ end
12
+ end
13
+
14
+ def self.hash_key full_mime_type_name
15
+ full_mime_type_name.match(/application\/vnd\.com\.chemcaster\.(.*)\+json/)
16
+ raise "No such media type: #{full_mime_type_name}" unless key = $1
17
+
18
+ begin
19
+ Object.const_get(key)
20
+ rescue
21
+ raise "No such class: #{key}"
22
+ end
23
+
24
+ key.downcase
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,6 @@
1
+ module Chemcaster
2
+ class Query < Item
3
+ attributes :molfile
4
+ resources :images, :registry
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ require File.dirname(__FILE__) + '/../chemcaster/item'
2
+
3
+ module Chemcaster
4
+ class Registry < Item
5
+ attributes :name, :deletable
6
+ resources :queries, :structures
7
+ end
8
+ end
@@ -0,0 +1,66 @@
1
+ module Chemcaster
2
+ class Representation
3
+ # class instance variables - see: http://martinfowler.com/bliki/ClassInstanceVariable.html
4
+ class << self; attr_accessor :resource_ids; end
5
+ class << self; attr_accessor :attribute_ids; end
6
+
7
+ attr_accessor :attributes
8
+ attr_accessor :link
9
+
10
+ def initialize link, raw
11
+ @link = link
12
+ @attributes = {}
13
+ load_hash raw
14
+ end
15
+
16
+ def self.attributes *atts
17
+ self.attribute_ids ||= []
18
+ atts.each do |m|
19
+ self.attribute_ids << m.to_s
20
+ define_method(m) do
21
+ attributes[m.to_s]
22
+ end
23
+
24
+ define_method("#{m}=") do |val|
25
+ attributes.merge!({m.to_s => val})
26
+ end
27
+ end
28
+ end
29
+
30
+ def self.resources *res
31
+ self.resource_ids ||= self.superclass.resource_ids || []
32
+ res.each do |id|
33
+ self.resource_ids << id
34
+ define_method(id) do
35
+ instance_variable_get("@#{id}_link").send('get')
36
+ end
37
+ end
38
+ end
39
+
40
+ def to_json
41
+ JSON({attributes_name => @attributes})
42
+ end
43
+
44
+ def attributes_name
45
+ self.class.to_s.gsub(/Chemcaster::/, '').downcase
46
+ end
47
+
48
+ protected
49
+
50
+ def load_hash hash
51
+ self.class.attribute_ids ||= []
52
+ if hash[name = attributes_name]
53
+ hash[name].each do |attribute|
54
+ if self.class.attribute_ids.member? attribute[0]
55
+ attributes[attribute[0]] = attribute[1]
56
+ end
57
+ end
58
+ end
59
+
60
+ self.class.resource_ids ||= []
61
+ self.class.resource_ids.each do |resource_id|
62
+ instance_variable_set("@#{resource_id}_link".to_sym, Link.new(hash[resource_id.to_s]))
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,41 @@
1
+ require File.dirname(__FILE__) + '/../chemcaster/representation'
2
+
3
+ module Chemcaster
4
+ class Service < Representation
5
+ attr_accessor :registries_link
6
+
7
+ # Ruby SSL needs to be told the location of the system's SSL CA files.
8
+ # On Debian Linux systems, these files are located at /etc/ssl/certs,
9
+ # which is this library's default. For more information, see:
10
+ #
11
+ # http://codeidol.com/other/rubyckbk/Internet-Services/Making-an-HTTPS-Web-Request
12
+ # http://redcorundum.blogspot.com/2008/03/ssl-certificates-and-nethttps.html
13
+ # http://notetoself.vrensk.com/2008/09/verified-https-in-ruby
14
+
15
+ @@root_ca = nil; def self.root_ca; @@root_ca; end
16
+ @@username = nil; def self.username; @@username; end
17
+ @@password = nil; def self.password; @@password; end
18
+
19
+ def self.connect username, password, options = {}
20
+ @@username = username; @@password = password
21
+
22
+ @@root_ca = options[:root_ca] || '/etc/ssl/certs'
23
+ uri = options[:uri] || 'https://chemcaster.com/rest'
24
+
25
+ service_link = Link.new 'uri' => uri,
26
+ 'media_type' => 'application/vnd.com.chemcaster.Service+json', 'name' => 'root'
27
+ service_link.get
28
+ end
29
+
30
+ def registries
31
+ @registries_link.get
32
+ end
33
+
34
+ protected
35
+
36
+ def load_hash hash
37
+ super
38
+ @registries_link = Link.new hash['registries']
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,6 @@
1
+ module Chemcaster
2
+ class Structure < Item
3
+ attributes :name, :molfile
4
+ resources :images, :registry
5
+ end
6
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: metamolecular-chemcaster-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Richard Apodaca
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-08-17 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: json_pure
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description: A hypertext-driven Ruby client for the Chemcaster cheminformatics Web services platform.
26
+ email: info@metamolecular.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - README.rdoc
35
+ - Rakefile
36
+ - lib/chemcaster.rb
37
+ - lib/chemcaster/error.rb
38
+ - lib/chemcaster/image.rb
39
+ - lib/chemcaster/index.rb
40
+ - lib/chemcaster/item.rb
41
+ - lib/chemcaster/link.rb
42
+ - lib/chemcaster/media_type.rb
43
+ - lib/chemcaster/query.rb
44
+ - lib/chemcaster/registry.rb
45
+ - lib/chemcaster/representation.rb
46
+ - lib/chemcaster/service.rb
47
+ - lib/chemcaster/structure.rb
48
+ has_rdoc: false
49
+ homepage: http://chemcaster.com
50
+ post_install_message:
51
+ rdoc_options: []
52
+
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: "0"
66
+ version:
67
+ requirements: []
68
+
69
+ rubyforge_project:
70
+ rubygems_version: 1.2.0
71
+ signing_key:
72
+ specification_version: 2
73
+ summary: A hypertext-driven Ruby client for the Chemcaster cheminformatics Web services platform. End.
74
+ test_files: []
75
+