investolink 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
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/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rest-client', '~> 1.4'
4
+ gem 'multi_json', '~> 1.1'
5
+ gem "activesupport", "~> 3.0"
6
+
7
+ # Specify your gem's dependencies in investolink.gemspec
8
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Crowdnetic
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,18 @@
1
+ # Investolink
2
+
3
+
4
+ ## Installation
5
+
6
+ Add this line to your application's Gemfile:
7
+
8
+ gem 'crowdnetic'
9
+
10
+ And then execute:
11
+
12
+ $ bundle
13
+
14
+ Or install it yourself as:
15
+
16
+ $ gem install crowdnetic
17
+
18
+
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.unshift(File.join(File.dirname(__FILE__), 'lib'))
3
+
4
+ require 'investolink/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.authors = ["Sri Goteti"]
8
+ gem.email = ["sri@crowdnetic.com"]
9
+ gem.description = %q{"Crowdnetic provides transparency for the private and crowdfunded securities marketplace.See http://www.crowdnetic.com for more details."}
10
+ gem.summary = %q{"Crowdnetic Ruby bindings for InvestoLink API"}
11
+ gem.homepage = "http://www.crowdnetic.com"
12
+
13
+ gem.files = `git ls-files`.split($\)
14
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
15
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
16
+ gem.name = "investolink"
17
+ gem.require_paths = ["lib"]
18
+ gem.version = Investolink::VERSION
19
+ end
@@ -0,0 +1,5 @@
1
+ module Investolink
2
+ class Asset < Resource
3
+ include Investolink::Operations::Update
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Investolink
2
+ class Donation < Resource
3
+ include Investolink::Operations::Update
4
+ end
5
+ end
@@ -0,0 +1,4 @@
1
+ module Investolink
2
+ class APIConnectionError < InvestolinkError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Investolink
2
+ class APIError < InvestolinkError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Investolink
2
+ class AuthenticationError < InvestolinkError
3
+ end
4
+ end
@@ -0,0 +1,10 @@
1
+ module Investolink
2
+ class InvalidRequestError < InvestolinkError
3
+ attr_accessor :param
4
+
5
+ def initialize(message, param, http_status=nil, http_body=nil, json_body=nil)
6
+ super(message, http_status, http_body, json_body)
7
+ @param = param
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,20 @@
1
+ module Investolink
2
+ class InvestolinkError < StandardError
3
+ attr_reader :message
4
+ attr_reader :http_status
5
+ attr_reader :http_body
6
+ attr_reader :json_body
7
+
8
+ def initialize(message=nil, http_status=nil, http_body=nil, json_body=nil)
9
+ @message = message
10
+ @http_status = http_status
11
+ @http_body = http_body
12
+ @json_body = json_body
13
+ end
14
+
15
+ def to_s
16
+ status_string = @http_status.nil? ? "" : "(Status #{@http_status}) "
17
+ "#{status_string}#{@message}"
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,5 @@
1
+ module Investolink
2
+ class Fundallocation < Resource
3
+ include Investolink::Operations::Update
4
+ end
5
+ end
@@ -0,0 +1,148 @@
1
+ module Investolink
2
+ class InvestolinkObject
3
+ include Enumerable
4
+
5
+ attr_accessor :api_key, :api_token
6
+ @@permanent_attributes = Set.new([:api_key, :api_token])
7
+
8
+ # The default :id method is deprecated and isn't useful to us
9
+ if method_defined?(:id)
10
+ undef :id
11
+ end
12
+
13
+ def initialize(id=nil, api_key=nil, api_token=nil)
14
+ @api_key = api_key
15
+ @api_token = api_token
16
+ @values = {}
17
+
18
+ @unsaved_values = Set.new
19
+ @transient_values = Set.new
20
+ self.id = id if id
21
+ end
22
+
23
+ def self.construct_from(values, api_key=nil, api_token=nil)
24
+ obj = self.new(values[:id], api_key, api_token)
25
+ obj.refresh_from(values, api_key, api_token)
26
+ obj
27
+ end
28
+
29
+ def to_s(*args)
30
+ Investolink::JSON.dump(@values, :pretty => true)
31
+ end
32
+
33
+ def inspect()
34
+ id_string = (self.respond_to?(:id) && !self.id.nil?) ? " id=#{self.id}" : ""
35
+ "#<#{self.class}:0x#{self.object_id.to_s(16)}#{id_string}> JSON: " + Investolink::JSON.dump(@values, :pretty => true)
36
+ end
37
+
38
+ def refresh_from(values, api_key, api_token, partial=false)
39
+ @api_key = api_key
40
+ @api_token = api_token
41
+
42
+ removed = partial ? Set.new : Set.new(@values.keys - values.keys)
43
+ added = Set.new(values.keys - @values.keys)
44
+
45
+ instance_eval do
46
+ remove_accessors(removed)
47
+ add_accessors(added)
48
+ end
49
+ removed.each do |k|
50
+ @values.delete(k)
51
+ @transient_values.add(k)
52
+ @unsaved_values.delete(k)
53
+ end
54
+ values.each do |k, v|
55
+ @values[k] = Util.convert_to_investolink_object(v, api_key, api_token)
56
+ @transient_values.delete(k)
57
+ @unsaved_values.delete(k)
58
+ end
59
+ end
60
+
61
+ def [](k)
62
+ k = k.to_sym if k.kind_of?(String)
63
+ @values[k]
64
+ end
65
+
66
+ def []=(k, v)
67
+ send(:"#{k}=", v)
68
+ end
69
+
70
+ def keys
71
+ @values.keys
72
+ end
73
+
74
+ def values
75
+ @values.values
76
+ end
77
+
78
+ def to_json(*a)
79
+ Investolink::JSON.dump(@values)
80
+ end
81
+
82
+ def as_json(*a)
83
+ @values.as_json(*a)
84
+ end
85
+
86
+ def to_hash
87
+ @values
88
+ end
89
+
90
+ def each(&blk)
91
+ @values.each(&blk)
92
+ end
93
+
94
+ protected
95
+
96
+ def metaclass
97
+ class << self; self; end
98
+ end
99
+
100
+ def remove_accessors(keys)
101
+ metaclass.instance_eval do
102
+ keys.each do |k|
103
+ next if @@permanent_attributes.include?(k)
104
+ k_eq = :"#{k}="
105
+ remove_method(k) if method_defined?(k)
106
+ remove_method(k_eq) if method_defined?(k_eq)
107
+ end
108
+ end
109
+ end
110
+
111
+ def add_accessors(keys)
112
+ metaclass.instance_eval do
113
+ keys.each do |k|
114
+ next if @@permanent_attributes.include?(k)
115
+ k_eq = :"#{k}="
116
+ define_method(k) { @values[k] }
117
+ define_method(k_eq) do |v|
118
+ @values[k] = v
119
+ @unsaved_values.add(k)
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ def method_missing(name, *args)
126
+ # TODO: only allow setting in updateable classes.
127
+ if name.to_s.end_with?('=')
128
+ attr = name.to_s[0...-1].to_sym
129
+ @values[attr] = args[0]
130
+ @unsaved_values.add(attr)
131
+ add_accessors([attr])
132
+ return
133
+ else
134
+ return @values[name] if @values.has_key?(name)
135
+ end
136
+
137
+ begin
138
+ super
139
+ rescue NoMethodError => e
140
+ if @transient_values.include?(name)
141
+ raise NoMethodError.new(e.message + ". HINT: The '#{name}' attribute was set in the past, however. It was then wiped when refreshing the object with the result returned by Crowdnetic's API, probably as a result of a save(). The attributes currently available on this object are: #{@values.keys.join(', ')}")
142
+ else
143
+ raise
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,27 @@
1
+ module Investolink
2
+ class Issue < Resource
3
+ include Investolink::Operations::Create
4
+ include Investolink::Operations::Update
5
+
6
+ def transactions(params={})
7
+ response, api_key, api_token = Investolink.request(:get, transactions_url, @api_key, @api_token, params)
8
+ Util.convert_to_investolink_object(response, api_key, api_token)
9
+ end
10
+
11
+ def new_transaction(params)
12
+ response, api_key, api_token = Investolink.request(:post, new_transaction_url(id), @api_key, @api_token, params)
13
+ Util.convert_to_investolink_object(response, api_key, api_token)
14
+ end
15
+
16
+ private
17
+
18
+ def transactions_url
19
+ resource_url + '/transactions'
20
+ end
21
+
22
+ def new_transaction_url(id)
23
+ "/issues/#{CGI.escape(id)}/new-transaction"
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,5 @@
1
+ module Investolink
2
+ class IssueTransaction < Resource
3
+ include Investolink::Operations::Update
4
+ end
5
+ end
@@ -0,0 +1,29 @@
1
+ module Investolink
2
+ class Issuer < Resource
3
+
4
+ def ownerships(params={})
5
+ response, api_key, api_token = Investolink.request(:get, ownership_url, @api_key, @api_token, params)
6
+ Util.convert_to_investolink_object(response, api_key, api_token)
7
+ end
8
+
9
+ def new_owner(params={})
10
+ response, api_key, api_token = Investolink.request(:post, new_ownership_url(id), @api_key, @api_token, params)
11
+ Util.convert_to_investolink_object(response, api_key, api_token)
12
+ end
13
+
14
+ private
15
+
16
+ def issues_url
17
+ resource_url + '/issues'
18
+ end
19
+
20
+ def ownership_url
21
+ resource_url + '/ownership'
22
+ end
23
+
24
+ def new_ownership_url(id)
25
+ "/issuers/#{CGI.escape(id)}/new-owner"
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,5 @@
1
+ module Investolink
2
+ class IssuerOwnership < Resource
3
+ include Investolink::Operations::Update
4
+ end
5
+ end
@@ -0,0 +1,21 @@
1
+ module Investolink
2
+ module JSON
3
+ if MultiJson.respond_to?(:dump)
4
+ def self.dump(*args)
5
+ MultiJson.dump(*args)
6
+ end
7
+
8
+ def self.load(*args)
9
+ MultiJson.load(*args)
10
+ end
11
+ else
12
+ def self.dump(*args)
13
+ MultiJson.encode(*args)
14
+ end
15
+
16
+ def self.load(*args)
17
+ MultiJson.decode(*args)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ module Investolink
2
+ module Operations
3
+ module Create
4
+ module ClassMethods
5
+ def create(params={}, api_key=nil, api_token=nil)
6
+ response, api_key, api_token = Investolink.request(:post, self.resource_url + '/new', api_key, api_token, params)
7
+ Util.convert_to_investolink_object(response, api_key, api_token)
8
+ end
9
+ end
10
+
11
+ def self.included(base)
12
+ base.extend(ClassMethods)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Investolink
2
+ module Operations
3
+ module List
4
+ module ClassMethods
5
+ def all(filters={}, api_key=nil, api_token=nil)
6
+ response, api_key, api_token = Investolink.request(:get, resource_url, api_key, api_token, filters)
7
+ Util.convert_to_investolink_object(response, api_key, api_token)
8
+ end
9
+ end
10
+
11
+ def self.included(base)
12
+ base.extend(ClassMethods)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ module Investolink
2
+ module Operations
3
+ module Update
4
+ def save
5
+ if @unsaved_values.length > 0
6
+ values = {}
7
+ @unsaved_values.each { |k| values[k] = @values[k] }
8
+ response, api_key = Investolink.request(:post, self.resource_url + '/update', @api_key, @api_token, values)
9
+ refresh_from(response, api_key, api_token)
10
+ end
11
+ self
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,98 @@
1
+ module Investolink
2
+ class Project < Resource
3
+ include Investolink::Operations::Create
4
+ include Investolink::Operations::Update
5
+
6
+ def rewards(params={})
7
+ response, api_key, api_token = Investolink.request(:get, rewards_url, @api_key, @api_token, params)
8
+ Util.convert_to_investolink_object(response, api_key, api_token)
9
+ end
10
+
11
+ def new_reward(params)
12
+ response, api_key, api_token = Investolink.request(:post, new_reward_url(id), @api_key, @api_token, params)
13
+ Util.convert_to_investolink_object(response, api_key, api_token)
14
+ end
15
+
16
+ def assets(params={})
17
+ response, api_key, api_token = Investolink.request(:get, assets_url, @api_key, @api_token, params)
18
+ Util.convert_to_investolink_object(response, api_key, api_token)
19
+ end
20
+
21
+ def new_asset(params)
22
+ response, api_key, api_token = Investolink.request(:post, new_asset_url(id), @api_key, @api_token, params)
23
+ Util.convert_to_investolink_object(response, api_key, api_token)
24
+ end
25
+
26
+ def sociallinks(params={})
27
+ response, api_key, api_token = Investolink.request(:get, sociallinks_url, @api_key, @api_token, params)
28
+ Util.convert_to_investolink_object(response, api_key, api_token)
29
+ end
30
+
31
+ def new_sociallink(params)
32
+ response, api_key, api_token = Investolink.request(:post, new_sociallink_url(id), @api_key, @api_token, params)
33
+ Util.convert_to_investolink_object(response, api_key, api_token)
34
+ end
35
+
36
+ def fundallocations(params={})
37
+ response, api_key, api_token = Investolink.request(:get, fundallocations_url, @api_key, @api_token, params)
38
+ Util.convert_to_investolink_object(response, api_key, api_token)
39
+ end
40
+
41
+ def new_fundallocation(params)
42
+ response, api_key, api_token = Investolink.request(:post, new_fundallocation_url(id), @api_key, @api_token, params)
43
+ Util.convert_to_investolink_object(response, api_key, api_token)
44
+ end
45
+
46
+ def donations(params={})
47
+ response, api_key, api_token = Investolink.request(:get, donations_url, @api_key, @api_token, params)
48
+ Util.convert_to_investolink_object(response, api_key, api_token)
49
+ end
50
+
51
+ def new_donation(params)
52
+ response, api_key, api_token = Investolink.request(:post, new_donation_url(id), @api_key, @api_token, params)
53
+ Util.convert_to_investolink_object(response, api_key, api_token)
54
+ end
55
+
56
+ private
57
+
58
+ def rewards_url
59
+ resource_url + '/rewards'
60
+ end
61
+
62
+ def new_reward_url(id)
63
+ "/projects/#{CGI.escape(id)}/new-reward"
64
+ end
65
+
66
+ def assets_url
67
+ resource_url + '/assets'
68
+ end
69
+
70
+ def new_asset_url(id)
71
+ "/projects/#{CGI.escape(id)}/new-asset"
72
+ end
73
+
74
+ def sociallinks_url
75
+ resource_url + '/sociallinks'
76
+ end
77
+
78
+ def new_sociallink_url(id)
79
+ "/projects/#{CGI.escape(id)}/new-sociallink"
80
+ end
81
+
82
+ def fundallocations_url
83
+ resource_url + '/fundallocations'
84
+ end
85
+
86
+ def new_fundallocation_url(id)
87
+ "/projects/#{CGI.escape(id)}/new-fundallocation"
88
+ end
89
+
90
+ def donations_url
91
+ resource_url + '/donations'
92
+ end
93
+
94
+ def new_donation_url(id)
95
+ "/projects/#{CGI.escape(id)}/new-donation"
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,31 @@
1
+ module Investolink
2
+ class Resource < InvestolinkObject
3
+ def self.resource_url
4
+ if self == Resource
5
+ raise NotImplementedError.new('Resource is an abstract class. You should perform actions on its subclasses (Issuer, Issue, etc.)')
6
+ end
7
+ shortname = self.name.split('::')[-1]
8
+ shortname = Util.to_underscore(shortname.to_s)
9
+ "/#{CGI.escape(shortname.downcase)}s"
10
+ end
11
+
12
+ def resource_url
13
+ unless id = self['id']
14
+ raise InvalidRequestError.new("Could not determine which URL to request: #{self.class} instance has invalid ID: #{id.inspect}", 'id')
15
+ end
16
+ "#{self.class.resource_url}/#{CGI.escape(id.to_s)}"
17
+ end
18
+
19
+ def refresh
20
+ response, api_key, api_token = Investolink.request(:get, resource_url, @api_key, @api_token)
21
+ refresh_from(response, api_key, api_token)
22
+ self
23
+ end
24
+
25
+ def self.retrieve(id, api_key=nil, api_token=nil)
26
+ instance = self.new(id, api_key, api_token)
27
+ instance.refresh
28
+ instance
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ module Investolink
2
+ class Reward < Resource
3
+ include Investolink::Operations::Update
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Investolink
2
+ class Sociallink < Resource
3
+ include Investolink::Operations::Update
4
+ end
5
+ end
@@ -0,0 +1,169 @@
1
+ module Investolink
2
+ class Subscriber < Resource
3
+
4
+ def self.search(params={})
5
+ response, api_key, api_token = Investolink.request(:get, search_url, @api_key, @api_token, params)
6
+ Util.convert_to_investolink_object(response, api_key, api_token)
7
+ end
8
+
9
+ def self.issue(id)
10
+ response, api_key, api_token = Investolink.request(:get, issue_url(id), @api_key, @api_token)
11
+ Util.convert_to_investolink_object(response, api_key, api_token)
12
+ end
13
+
14
+ def self.issuer(id)
15
+ response, api_key, api_token = Investolink.request(:get, issuer_url(id), @api_key, @api_token)
16
+ Util.convert_to_investolink_object(response, api_key, api_token)
17
+ end
18
+
19
+ def self.transaction(id)
20
+ response, api_key, api_token = Investolink.request(:get, transaction_url(id), @api_key, @api_token)
21
+ Util.convert_to_investolink_object(response, api_key, api_token)
22
+ end
23
+
24
+ def self.owner(id)
25
+ response, api_key, api_token = Investolink.request(:get, owner_url(id), @api_key, @api_token)
26
+ Util.convert_to_investolink_object(response, api_key, api_token)
27
+ end
28
+
29
+ def self.issue_transactions(id)
30
+ response, api_key, api_token = Investolink.request(:get, issue_transactions_url(id), @api_key, @api_token)
31
+ Util.convert_to_investolink_object(response, api_key, api_token)
32
+ end
33
+
34
+ def self.issuer_owners(id)
35
+ response, api_key, api_token = Investolink.request(:get, issuer_owners_url(id), @api_key, @api_token)
36
+ Util.convert_to_investolink_object(response, api_key, api_token)
37
+ end
38
+
39
+ def self.project(id)
40
+ response, api_key, api_token = Investolink.request(:get, project_url(id), @api_key, @api_token)
41
+ Util.convert_to_investolink_object(response, api_key, api_token)
42
+ end
43
+
44
+ def self.reward(id)
45
+ response, api_key, api_token = Investolink.request(:get, reward_url(id), @api_key, @api_token)
46
+ Util.convert_to_investolink_object(response, api_key, api_token)
47
+ end
48
+
49
+ def self.rewards(id)
50
+ response, api_key, api_token = Investolink.request(:get, rewards_url(id), @api_key, @api_token)
51
+ Util.convert_to_investolink_object(response, api_key, api_token)
52
+ end
53
+
54
+ def self.donation(id)
55
+ response, api_key, api_token = Investolink.request(:get, donation_url(id), @api_key, @api_token)
56
+ Util.convert_to_investolink_object(response, api_key, api_token)
57
+ end
58
+
59
+ def self.donations(id)
60
+ response, api_key, api_token = Investolink.request(:get, donations_url(id), @api_key, @api_token)
61
+ Util.convert_to_investolink_object(response, api_key, api_token)
62
+ end
63
+
64
+ def self.asset(id)
65
+ response, api_key, api_token = Investolink.request(:get, asset_url(id), @api_key, @api_token)
66
+ Util.convert_to_investolink_object(response, api_key, api_token)
67
+ end
68
+
69
+ def self.assets(id)
70
+ response, api_key, api_token = Investolink.request(:get, assets_url(id), @api_key, @api_token)
71
+ Util.convert_to_investolink_object(response, api_key, api_token)
72
+ end
73
+
74
+ def self.fundallocation(id)
75
+ response, api_key, api_token = Investolink.request(:get, fundallocation_url(id), @api_key, @api_token)
76
+ Util.convert_to_investolink_object(response, api_key, api_token)
77
+ end
78
+
79
+ def self.fundallocations(id)
80
+ response, api_key, api_token = Investolink.request(:get, fundallocations_url(id), @api_key, @api_token)
81
+ Util.convert_to_investolink_object(response, api_key, api_token)
82
+ end
83
+
84
+ def self.sociallink(id)
85
+ response, api_key, api_token = Investolink.request(:get, sociallink_url(id), @api_key, @api_token)
86
+ Util.convert_to_investolink_object(response, api_key, api_token)
87
+ end
88
+
89
+ def self.sociallinks(id)
90
+ response, api_key, api_token = Investolink.request(:get, sociallinks_url(id), @api_key, @api_token)
91
+ Util.convert_to_investolink_object(response, api_key, api_token)
92
+ end
93
+
94
+ private
95
+
96
+ def self.search_url
97
+ "/feed/search"
98
+ end
99
+
100
+ def self.issue_url(id)
101
+ "/feed/issues/#{CGI.escape(id)}"
102
+ end
103
+
104
+ def self.issuer_url(id)
105
+ "/feed/issuer/#{id}"
106
+ end
107
+
108
+ def self.issue_transactions_url(id)
109
+ "/feed/issues/#{id}/transactions"
110
+ end
111
+
112
+ def self.issuer_owners_url(id)
113
+ "/feed/issuer/#{id}/ownership"
114
+ end
115
+
116
+ def self.transaction_url(id)
117
+ "/feed/issue-transactions/#{id}"
118
+ end
119
+
120
+ def self.owner_url(id)
121
+ "/feed/issuer-ownerships/#{id}"
122
+ end
123
+
124
+ def self.project_url(id)
125
+ "/feed/projects/#{CGI.escape(id)}"
126
+ end
127
+
128
+ def self.reward_url(id)
129
+ "/feed/rewards/#{id}"
130
+ end
131
+
132
+ def self.rewards_url(id)
133
+ "/feed/issues/#{id}/rewards"
134
+ end
135
+
136
+ def self.donation_url(id)
137
+ "/feed/donations/#{id}"
138
+ end
139
+
140
+ def self.donations_url(id)
141
+ "/feed/issues/#{id}/donations"
142
+ end
143
+
144
+ def self.asset_url(id)
145
+ "/feed/assets/#{id}"
146
+ end
147
+
148
+ def self.assets_url(id)
149
+ "/feed/issues/#{id}/assets"
150
+ end
151
+
152
+ def self.fundallocation_url(id)
153
+ "/feed/fundallocations/#{id}"
154
+ end
155
+
156
+ def self.fundallocations_url(id)
157
+ "/feed/issues/#{id}/fundallocations"
158
+ end
159
+
160
+ def self.sociallink_url(id)
161
+ "/feed/sociallinks/#{id}"
162
+ end
163
+
164
+ def self.sociallinks_url(id)
165
+ "/feed/issues/#{id}/sociallinks"
166
+ end
167
+
168
+ end
169
+ end
@@ -0,0 +1,110 @@
1
+ module Investolink
2
+ module Util
3
+ def self.objects_to_ids(h)
4
+ case h
5
+ when Resource
6
+ h.id
7
+ when Hash
8
+ res = {}
9
+ h.each { |k, v| res[k] = objects_to_ids(v) unless v.nil? }
10
+ res
11
+ when Array
12
+ h.map { |v| objects_to_ids(v) }
13
+ else
14
+ h
15
+ end
16
+ end
17
+
18
+ def self.convert_to_investolink_object(resp, api_key, api_token)
19
+ types = {
20
+ 'issuer' => Issuer,
21
+ 'issue' => Issue,
22
+ 'issue-transaction' => IssueTransaction,
23
+ 'issuer-ownership' => IssuerOwnership,
24
+ 'project' => Project,
25
+ 'reward' => Reward,
26
+ 'donation' => Donation,
27
+ 'asset' => Asset,
28
+ 'fundallocation' => Fundallocation,
29
+ 'sociallink' => Sociallink,
30
+ }
31
+ case resp
32
+ when Array
33
+ resp.map { |i| convert_to_investolink_object(i, api_key, api_token) }
34
+ when Hash
35
+ # Try converting to a known object class. If none available, fall back to generic Resource
36
+ if klass_name = resp[:object]
37
+ klass = types[klass_name]
38
+ end
39
+ klass ||= InvestolinkObject
40
+ klass.construct_from(resp, api_key, api_token)
41
+ else
42
+ resp
43
+ end
44
+ end
45
+
46
+ def self.file_readable(file)
47
+ begin
48
+ File.open(file) { |f| }
49
+ rescue
50
+ false
51
+ else
52
+ true
53
+ end
54
+ end
55
+
56
+ def self.symbolize_names(object)
57
+ case object
58
+ when Hash
59
+ new = {}
60
+ object.each do |key, value|
61
+ key = (key.to_sym rescue key) || key
62
+ new[key] = symbolize_names(value)
63
+ end
64
+ new
65
+ when Array
66
+ object.map { |value| symbolize_names(value) }
67
+ else
68
+ object
69
+ end
70
+ end
71
+
72
+ def self.encode_key(key)
73
+ URI.escape(key.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
74
+ end
75
+
76
+ def self.flatten_params(params, parent_key=nil)
77
+ result = []
78
+ params.each do |key, value|
79
+ calculated_key = parent_key ? "#{parent_key}[#{encode_key(key)}]" : encode_key(key)
80
+ if value.is_a?(Hash)
81
+ result += flatten_params(value, calculated_key)
82
+ elsif value.is_a?(Array)
83
+ result += flatten_params_array(value, calculated_key)
84
+ else
85
+ result << [calculated_key, value]
86
+ end
87
+ end
88
+ result
89
+ end
90
+
91
+ def self.flatten_params_array(value, calculated_key)
92
+ result = []
93
+ value.each do |elem|
94
+ if elem.is_a?(Hash)
95
+ result += flatten_params(elem, calculated_key)
96
+ elsif elem.is_a?(Array)
97
+ result += flatten_params_array(elem, calculated_key)
98
+ else
99
+ result << ["#{calculated_key}[]", elem]
100
+ end
101
+ end
102
+ result
103
+ end
104
+
105
+ def self.to_underscore(text)
106
+ text.gsub(/(.)([A-Z])/,'\1-\2').downcase
107
+ end
108
+
109
+ end
110
+ end
@@ -0,0 +1,3 @@
1
+ module Investolink
2
+ VERSION = "1.0.2"
3
+ end
@@ -0,0 +1,240 @@
1
+ require 'cgi'
2
+ require 'set'
3
+ require 'rubygems'
4
+ require 'openssl'
5
+
6
+ gem 'rest-client', '~> 1.4'
7
+ require 'rest_client'
8
+ require 'multi_json'
9
+
10
+ #Version
11
+ require "investolink/version"
12
+
13
+ #API Operations
14
+ require "investolink/operations/create"
15
+ #require "investolink/operations/list"
16
+ require "investolink/operations/update"
17
+
18
+ #Resources
19
+ require "investolink/util"
20
+ require "investolink/json"
21
+ require "investolink/investolink_object"
22
+ require "investolink/resource"
23
+ require "investolink/issuer"
24
+ require "investolink/issue"
25
+ require "investolink/issue_transaction"
26
+ require "investolink/issuer_ownership"
27
+ require "investolink/project"
28
+ require "investolink/asset"
29
+ require "investolink/donation"
30
+ require "investolink/sociallink"
31
+ require "investolink/fundallocation"
32
+ require "investolink/reward"
33
+ require "investolink/subscriber"
34
+
35
+ #Errors
36
+ require "investolink/errors/investolink_error"
37
+ require "investolink/errors/api_connection_error"
38
+ require "investolink/errors/api_error"
39
+ require "investolink/errors/authentication_error"
40
+ require "investolink/errors/invalid_request_error"
41
+
42
+
43
+ module Investolink
44
+ @@api_key = nil
45
+ @@api_token = nil
46
+ @@api_base = "https://api.crowdnetic.com/v1"
47
+
48
+ def self.api_url(url='')
49
+ @@api_base + url
50
+ end
51
+
52
+ def self.api_key=(api_key)
53
+ @@api_key = api_key
54
+ end
55
+
56
+ def self.api_key
57
+ @@api_key
58
+ end
59
+
60
+ def self.api_base=(api_base)
61
+ @@api_base = api_base
62
+ end
63
+
64
+ def self.api_base
65
+ @@api_base
66
+ end
67
+
68
+ def self.api_token=(api_token)
69
+ @@api_token = api_token
70
+ end
71
+
72
+ def self.api_token
73
+ @@api_token
74
+ end
75
+
76
+ def self.request(method, url, api_key, api_token, params=nil, headers={})
77
+ api_key ||= @@api_key
78
+ api_token ||= @@api_token
79
+ raise AuthenticationError.new('No API key provided. (HINT: set your API key using "Investolink.api_key = <API-KEY> and Investolink.api_token = <API-TOKEN>". You can generate API keys from the Crowdnetic web interface. See http://www.crowdnetic.com for details, or email support-api@crowdnetic.com if you have any questions.)') unless api_key
80
+
81
+ =begin
82
+ if !verify_ssl_certs
83
+ unless @no_verify
84
+ $stderr.puts "WARNING: Running without SSL cert verification. Execute 'Investolink.verify_ssl_certs = true' to enable verification."
85
+ @no_verify = true
86
+ end
87
+ ssl_opts = { :verify_ssl => false }
88
+ elsif !Util.file_readable(@@ssl_bundle_path)
89
+ unless @no_bundle
90
+ $stderr.puts "WARNING: Running without SSL cert verification because #{@@ssl_bundle_path} isn't readable"
91
+ @no_bundle = true
92
+ end
93
+ ssl_opts = { :verify_ssl => false }
94
+ else
95
+ ssl_opts = {
96
+ :verify_ssl => OpenSSL::SSL::VERIFY_PEER,
97
+ :ssl_ca_file => @@ssl_bundle_path
98
+ }
99
+ end
100
+ =end
101
+ ssl_opts = {}
102
+
103
+ uname = (@@uname ||= RUBY_PLATFORM =~ /linux|darwin/i ? `uname -a 2>/dev/null`.strip : nil)
104
+ lang_version = "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})"
105
+ ua = {
106
+ :bindings_version => Investolink::VERSION,
107
+ :lang => 'ruby',
108
+ :lang_version => lang_version,
109
+ :platform => RUBY_PLATFORM,
110
+ :publisher => 'investolink',
111
+ :uname => uname
112
+ }
113
+
114
+ params = Util.objects_to_ids(params)
115
+ url = self.api_url(url) + ".json"
116
+ case method.to_s.downcase.to_sym
117
+ when :get, :head, :delete
118
+ # Make params into GET parameters
119
+ if params && params.count
120
+ query_string = Util.flatten_params(params).collect{|p| "#{p[0]}=#{p[1]}"}.join('&')
121
+ url += "?#{query_string}"
122
+ end
123
+ payload = nil
124
+ else
125
+ payload = params
126
+ end
127
+
128
+ begin
129
+ headers = { :x_investolink_client_user_agent => Investolink::JSON.dump(ua) }.merge(headers)
130
+ rescue => e
131
+ headers = {
132
+ :x_investolink_client_raw_user_agent => ua.inspect,
133
+ :error => "#{e} (#{e.class})"
134
+ }.merge(headers)
135
+ end
136
+
137
+ headers = {
138
+ :user_agent => "Investolink/v1 RubyBindings/#{Investolink::VERSION}",
139
+ :x_api_key => "#{api_key}",
140
+ :x_api_token => "#{api_token}"
141
+ }.merge(headers)
142
+ opts = {
143
+ :method => method,
144
+ :url => url,
145
+ :headers => headers,
146
+ :open_timeout => 30,
147
+ :payload => payload,
148
+ :timeout => 80
149
+ }.merge(ssl_opts)
150
+
151
+ begin
152
+ response = execute_request(opts)
153
+ rescue SocketError => e
154
+ self.handle_restclient_error(e)
155
+ rescue NoMethodError => e
156
+ # Work around RestClient bug
157
+ if e.error_message =~ /\WRequestFailed\W/
158
+ e = APIConnectionError.new('Unexpected HTTP response code')
159
+ self.handle_restclient_error(e)
160
+ else
161
+ raise
162
+ end
163
+ rescue RestClient::ExceptionWithResponse => e
164
+ if rcode = e.http_code and rbody = e.http_body
165
+ self.handle_api_error(rcode, rbody)
166
+ else
167
+ self.handle_restclient_error(e)
168
+ end
169
+ rescue RestClient::Exception, Errno::ECONNREFUSED => e
170
+ self.handle_restclient_error(e)
171
+ end
172
+
173
+ rbody = response.body
174
+ rcode = response.code
175
+ begin
176
+ # Would use :symbolize_names => true, but apparently there is
177
+ # some library out there that makes symbolize_names not work.
178
+ resp = Investolink::JSON.load(rbody)
179
+ rescue MultiJson::DecodeError
180
+ raise APIError.new("Invalid response object from API: #{rbody.inspect} (HTTP response code was #{rcode})", rcode, rbody)
181
+ end
182
+
183
+ resp = Util.symbolize_names(resp)
184
+ [resp, api_key, api_token]
185
+ end
186
+
187
+ private
188
+
189
+ def self.execute_request(opts)
190
+ RestClient::Request.execute(opts)
191
+ end
192
+
193
+ def self.handle_api_error(rcode, rbody)
194
+ begin
195
+ error_obj = Investolink::JSON.load(rbody)
196
+ error_obj = Util.symbolize_names(error_obj)
197
+ error = error_obj[:error] or raise InvestolinkError.new # escape from parsing
198
+ rescue MultiJson::DecodeError, InvestolinkError
199
+ raise APIError.new("Invalid response object from API: #{rbody.inspect} (HTTP response code was #{rcode})", rcode, rbody)
200
+ end
201
+
202
+ case rcode
203
+ when 400, 404 then
204
+ raise invalid_request_error(error, rcode, rbody, error_obj)
205
+ when 401
206
+ raise authentication_error(error, rcode, rbody, error_obj)
207
+ when 402
208
+ else
209
+ raise api_error(error, rcode, rbody, error_obj)
210
+ end
211
+ end
212
+
213
+ def self.invalid_request_error(error, rcode, rbody, error_obj)
214
+ InvalidRequestError.new(error[:error_message], error[:param], rcode, rbody, error_obj)
215
+ end
216
+
217
+ def self.authentication_error(error, rcode, rbody, error_obj)
218
+ AuthenticationError.new(error[:error_message], rcode, rbody, error_obj)
219
+ end
220
+
221
+ def self.api_error(error, rcode, rbody, error_obj)
222
+ APIError.new(error[:error_message], rcode, rbody, error_obj)
223
+ end
224
+
225
+ def self.handle_restclient_error(e)
226
+ case e
227
+ when RestClient::ServerBrokeConnection, RestClient::RequestTimeout
228
+ message = "Could not connect to Crowdnetic (#{@@api_base}). Please check your internet connection and try again. If this problem persists, please let us know at support-api@crowdnetic.com."
229
+ when RestClient::SSLCertificateNotVerified
230
+ message = "Could not verify Crowdnetic's SSL certificate. Please make sure that your network is not intercepting certificates. (Try going to https://api.crowdnetic.com/v1 in your browser.) If this problem persists, let us know at support-api@crowdnetic.com."
231
+ when SocketError
232
+ message = "Unexpected error communicating when trying to connect to Crowdnetic. HINT: You may be seeing this message because your DNS is not working. To check, try running 'host Crowdnetic.com' from the command line."
233
+ else
234
+ message = "Unexpected error communicating with Crowdnetic. If this problem persists, let us know at support-api@crowdnetic.com."
235
+ end
236
+ message += "\n\n(Network error: #{e.message})"
237
+ raise APIConnectionError.new(message)
238
+ end
239
+
240
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: investolink
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sri Goteti
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-07-25 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: ! '"Crowdnetic provides transparency for the private and crowdfunded
15
+ securities marketplace.See http://www.crowdnetic.com for more details."'
16
+ email:
17
+ - sri@crowdnetic.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - .gitignore
23
+ - Gemfile
24
+ - LICENSE
25
+ - README.md
26
+ - Rakefile
27
+ - investolink.gemspec
28
+ - lib/investolink.rb
29
+ - lib/investolink/asset.rb
30
+ - lib/investolink/donation.rb
31
+ - lib/investolink/errors/api_connection_error.rb
32
+ - lib/investolink/errors/api_error.rb
33
+ - lib/investolink/errors/authentication_error.rb
34
+ - lib/investolink/errors/invalid_request_error.rb
35
+ - lib/investolink/errors/investolink_error.rb
36
+ - lib/investolink/fundallocation.rb
37
+ - lib/investolink/investolink_object.rb
38
+ - lib/investolink/issue.rb
39
+ - lib/investolink/issue_transaction.rb
40
+ - lib/investolink/issuer.rb
41
+ - lib/investolink/issuer_ownership.rb
42
+ - lib/investolink/json.rb
43
+ - lib/investolink/operations/create.rb
44
+ - lib/investolink/operations/list.rb
45
+ - lib/investolink/operations/update.rb
46
+ - lib/investolink/project.rb
47
+ - lib/investolink/resource.rb
48
+ - lib/investolink/reward.rb
49
+ - lib/investolink/sociallink.rb
50
+ - lib/investolink/subscriber.rb
51
+ - lib/investolink/util.rb
52
+ - lib/investolink/version.rb
53
+ homepage: http://www.crowdnetic.com
54
+ licenses: []
55
+ post_install_message:
56
+ rdoc_options: []
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ! '>='
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ requirements: []
72
+ rubyforge_project:
73
+ rubygems_version: 1.8.24
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: ! '"Crowdnetic Ruby bindings for InvestoLink API"'
77
+ test_files: []