hookercookerman-amee 0.0.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.
Files changed (80) hide show
  1. data/History.txt +1 -0
  2. data/LICENSE.txt +20 -0
  3. data/Manifest.txt +79 -0
  4. data/README.rdoc +33 -0
  5. data/Rakefile +29 -0
  6. data/features/config.feature +22 -0
  7. data/features/data/data_category.feature +26 -0
  8. data/features/data/data_item.feature +19 -0
  9. data/features/data/data_item_value.feature +17 -0
  10. data/features/data/drill_down.feature +48 -0
  11. data/features/development.feature +13 -0
  12. data/features/profile/create.profile.feature +15 -0
  13. data/features/profile/create.profile_item.feature +12 -0
  14. data/features/profile/delete.profile.feature +12 -0
  15. data/features/profile/delete.profile_item.feature +13 -0
  16. data/features/profile/get.profile.feature +13 -0
  17. data/features/profile/profile_category.feature +14 -0
  18. data/features/profile/profile_item.feature +15 -0
  19. data/features/profile/profiles.feature +15 -0
  20. data/features/profile/update.profile_item.feature +14 -0
  21. data/features/session/reauthenticate.feature +16 -0
  22. data/features/step_definitions/amee_steps.rb +67 -0
  23. data/features/step_definitions/common_steps.rb +194 -0
  24. data/features/step_definitions/config_steps.rb +13 -0
  25. data/features/step_definitions/data_steps.rb +142 -0
  26. data/features/step_definitions/profile_category_steps.rb +23 -0
  27. data/features/step_definitions/profile_item_steps.rb +62 -0
  28. data/features/step_definitions/profile_steps.rb +41 -0
  29. data/features/support/amee/auth/response.json +11 -0
  30. data/features/support/amee/data.json +84 -0
  31. data/features/support/amee/data/transport/car/generic.json +3 -0
  32. data/features/support/amee/data/transport/car/generic/drill.json +66 -0
  33. data/features/support/amee/data/transport/car/generic/drill?fuel=diesel&size=large.json +55 -0
  34. data/features/support/amee/data/transport/car/generic/drill?fuel=diesel.json +59 -0
  35. data/features/support/amee/data/transport/plane/generic.json +225 -0
  36. data/features/support/amee/data/transport/plane/generic/FFC7A05D54AD.json +224 -0
  37. data/features/support/amee/data/transport/plane/generic/FFC7A05D54AD/kgCO2PerPassengerJourney.json +42 -0
  38. data/features/support/amee/data_category.json +84 -0
  39. data/features/support/amee/data_category_with_data_items.json +225 -0
  40. data/features/support/amee/profiles.json +73 -0
  41. data/features/support/amee/profiles/155DD3C63646/transport/motorcycle/generic/D47C465B8157.json +190 -0
  42. data/features/support/amee/profiles/155DD3C63646/transport/motorcycle/generic/D47C465B8157?distance=400&representation=true.json +190 -0
  43. data/features/support/amee/profiles/48B97680BCCF/home/energy/quantity/response.json +9 -0
  44. data/features/support/amee/profiles/7C7D68C2A7CD/home.json +65 -0
  45. data/features/support/amee/profiles/BB1BDB4FDD77/home/energy/quantity/920B54ED665B.json +201 -0
  46. data/features/support/amee/profiles/E0BCB3704D15.json +19 -0
  47. data/features/support/amee/profiles/E0BCB3704D15/Business.json +6 -0
  48. data/features/support/amee/profiles/profile.json +27 -0
  49. data/features/support/env.rb +24 -0
  50. data/init.rb +4 -0
  51. data/lib/amee.rb +37 -0
  52. data/lib/amee/config.rb +59 -0
  53. data/lib/amee/data_api/data_category.rb +50 -0
  54. data/lib/amee/data_api/data_item.rb +28 -0
  55. data/lib/amee/data_api/data_item_value.rb +13 -0
  56. data/lib/amee/data_api/drill_down.rb +23 -0
  57. data/lib/amee/data_api/item_definition.rb +11 -0
  58. data/lib/amee/data_api/item_value_definition.rb +13 -0
  59. data/lib/amee/data_api/value_definition.rb +10 -0
  60. data/lib/amee/logging.rb +43 -0
  61. data/lib/amee/model.rb +128 -0
  62. data/lib/amee/parser.rb +137 -0
  63. data/lib/amee/profile_api/profile.rb +39 -0
  64. data/lib/amee/profile_api/profile_category.rb +42 -0
  65. data/lib/amee/profile_api/profile_item.rb +47 -0
  66. data/lib/amee/service.rb +78 -0
  67. data/lib/amee/session.rb +222 -0
  68. data/lib/amee/utils/string.rb +11 -0
  69. data/script/console +10 -0
  70. data/script/destroy +14 -0
  71. data/script/generate +14 -0
  72. data/script/txt2html +71 -0
  73. data/spec/amee_spec.rb +1 -0
  74. data/spec/service_spec.rb +53 -0
  75. data/spec/session_spec.rb +45 -0
  76. data/spec/spec.opts +1 -0
  77. data/spec/spec_helper.rb +19 -0
  78. data/tasks/rspec.rake +21 -0
  79. data/tasks/yard.rake +4 -0
  80. metadata +184 -0
@@ -0,0 +1,39 @@
1
+ require "amee/profile_api/profile_category"
2
+ require "amee/profile_api/profile_item"
3
+ module Amee
4
+ module ProfileApi
5
+ class Profile
6
+ include ::Amee::Model
7
+ self.path_prefix = "/profiles"
8
+
9
+ attr_accessor :profile_date, :amount_per_month
10
+ list_populators :profile_categories => {:class => Amee::ProfileApi::ProfileCategory}
11
+ item_populators :data_category => {:class => Amee::ProfileApi::ProfileCategory}
12
+
13
+ def self.create(session)
14
+ self.from_hash(session.new_profile, session)
15
+ end
16
+
17
+ def create_profile_data_item(path_or_category, data_item_uid, params = {})
18
+ path = self.full_path + path_or_category.is_a?(String) ? "/#{path_or_category}" : "/#{path_or_category.full_path}"
19
+ Amee::ProfileApi::ProfileDataItem.create(session, path, data_item_uid, params)
20
+ end
21
+
22
+ def get_profile_item(path, options = {})
23
+ session.get_profile_item(path, options)
24
+ end
25
+
26
+ def update_profile_item(path, fields)
27
+ session.update_profile_item(full_path, :fields => fields)
28
+ end
29
+
30
+ def destroy
31
+ session.delete_profile(self.uid)
32
+ end
33
+
34
+ def full_path
35
+ "#{self.class.path_prefix}/#{self.uid}"
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,42 @@
1
+ require "amee/profile_api/profile_item"
2
+ require "amee/data_api/data_category"
3
+ module Amee
4
+ module ProfileApi
5
+ class ProfileCategory
6
+ include ::Amee::Model
7
+ self.path_prefix = "/profiles"
8
+
9
+
10
+ attr_accessor :profile, :total_amount_per_month, :total_amount
11
+
12
+ list_populators :profile_items => {:class => Amee::ProfileApi::ProfileItem},
13
+ :profile_categories => {:class => Amee::ProfileApi::ProfileCategory}
14
+
15
+ item_populators :data_category => {:class => Amee::DataApi::DataCategory}
16
+
17
+ def populate!
18
+ session.api_call(:get, "profile.category", self.full_path) do |response|
19
+ populate_from_hash!(response)
20
+ end
21
+ end
22
+
23
+ def profile_uid
24
+ profile["uid"]
25
+ end
26
+
27
+ def total_co2_unit
28
+ total_amount["unit"]
29
+ end
30
+
31
+ def total_co2_value
32
+ total_amount["value"]
33
+ end
34
+
35
+ def full_path
36
+ "#{self.class.path_prefix}/#{profile_uid}" + resource_path
37
+ end
38
+
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,47 @@
1
+ require "amee/data_api/data_category"
2
+ require "amee/data_api/data_item_value"
3
+ module Amee
4
+ module ProfileApi
5
+ class ProfileItem
6
+ include Amee::Model
7
+ self.path_prefix = "/profiles"
8
+
9
+ attr_accessor :end, :amount, :data_item, :profile, :valid_from, :start_date, :end_date, :data_item, :amount_per_month, :total_amount
10
+
11
+ list_populators :item_values => {:class => Amee::DataApi::DataItemValue}
12
+ item_populators :data_category => {:class => Amee::DataApi::DataCategory},
13
+ :item_definition => {:class => Amee::DataApi::ItemDefinition}
14
+
15
+
16
+ def self.create(session, path, data_item_uid, fields ={})
17
+ hash = session.create_profile_data_category(path, data_item_uid, :fields => fields)
18
+ self.from_hash(hash, session)
19
+ end
20
+
21
+ def update(fields)
22
+ session.update_profile_item(self.full_path, :fields => fields)
23
+ end
24
+
25
+ def destroy
26
+ session.delete_profile_item(self.full_path)
27
+ end
28
+
29
+ def co2_unit
30
+ amount["unit"]
31
+ end
32
+
33
+ def co2_value
34
+ amount["value"]
35
+ end
36
+
37
+ def profile_uid
38
+ profile["uid"]
39
+ end
40
+
41
+ def full_path
42
+ "#{self.class.path_prefix}/#{profile_uid}" + resource_path
43
+ end
44
+
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,78 @@
1
+ require 'net/http'
2
+ module Amee
3
+ class Service
4
+ include HTTParty
5
+ base_uri Amee::Config[:server]
6
+ format :json
7
+
8
+ def initialize(auth_token)
9
+ @auth_token = auth_token
10
+ end
11
+
12
+ def post(method, path, options = {})
13
+ perform_request(:post, method, path, options)
14
+ end
15
+
16
+ def get(method, path, options = {})
17
+ perform_request(:get, method, path, options)
18
+ end
19
+
20
+ def put(method, path, options = {})
21
+ perform_request(:put, method, path, options)
22
+ end
23
+
24
+ def delete(method, path, options = {})
25
+ perform_request(:delete, method, path, options)
26
+ end
27
+
28
+ def self.auth_token(username, password, path)
29
+ response = Net::HTTP.post_form(
30
+ URI.parse(self.base_uri + path),
31
+ {'username'=> username, 'password'=>password}
32
+ )
33
+ response['authToken']
34
+ end
35
+
36
+ private
37
+ # we want to attach the authToken to the headers of the request
38
+ # and then check the status code
39
+ def perform_request(type, method, path, options)
40
+ attach_headers(options)
41
+ response = self.class.send(type, path, options)
42
+ check_response(response.code)
43
+ Parser.parse(method, response)
44
+ end
45
+
46
+ def attach_headers(options)
47
+ (options[:headers] ||= {}).merge!(
48
+ {
49
+ "authToken" => @auth_token,
50
+ 'Accept' => options[:accept] || Amee::Config[:accept]
51
+ }
52
+ )
53
+ end
54
+
55
+ # checking the status code of the response; if we are not authenticated
56
+ # then authenticate the session
57
+ #
58
+ # @raise [Amee::PermissionDenied] if the status code is 403
59
+ # @raise [Amee::UnAuthorized] if a auth_token could not be generated
60
+ # @raise [Amee::SessionExpired] if a we get a 401
61
+ # @raise [Amee::UnknownError] if we get something strange
62
+ def check_response(code)
63
+ case code
64
+ when 200, 201
65
+ true
66
+ when 403
67
+ raise Amee::Session::PermissionDenied.new("You do not have permission to perform the requested operation")
68
+ when 401
69
+ raise Amee::Session::Expired.new("Session has expired")
70
+ when 404
71
+ raise Amee::Session::NotFound.new("resource was not found")
72
+ else
73
+ raise Amee::Session::UnknownError.new("super strange type unknown error")
74
+ end
75
+ end
76
+
77
+ end
78
+ end
@@ -0,0 +1,222 @@
1
+ module Amee
2
+ class Session
3
+
4
+ class Expired < StandardError; end
5
+ class UnAuthorized < StandardError; end
6
+ class NotAuthenticated < StandardError; end
7
+ class PermissionDenied < StandardError; end
8
+ class NotFound < StandardError; end
9
+ class UnknownError < StandardError; end
10
+ attr_accessor :auth_token, :cache
11
+
12
+ def self.create(username = nil, password = nil)
13
+ username ||= Amee::Config[:username]
14
+ password ||= Amee::Config[:password]
15
+ raise ArgumentError unless !username.nil? && !password.nil?
16
+ new(username, password)
17
+ end
18
+
19
+ def initialize(username, password, authenticate = true)
20
+ @username = username
21
+ @password = password
22
+ @cache = create_cache_store if caching?
23
+ authenticate! if authenticate
24
+ end
25
+
26
+ # We create a cache store vie using the config cache_store and parameters if
27
+ # they exist; Moneta Stores are only supported
28
+ # @return [Moneta::Store]
29
+ def create_cache_store
30
+ @cache = Amee::Config[:cache_store].send(:new, *Amee::Config[:cache_store_parameters] || nil)
31
+ end
32
+
33
+ # @return [Boolean] are we caching?
34
+ def caching?
35
+ Amee::Config[:cache]
36
+ end
37
+
38
+ def authenticate!
39
+ @auth_token = nil
40
+ unless @auth_token = Amee::Service.auth_token(@username, @password, Amee::Config[:auth_path])
41
+ raise Amee::Session::UnAuthorized.new "Please provide your correct username and password. "
42
+ end
43
+ end
44
+
45
+ def authenticated?
46
+ !@auth_token.nil?
47
+ end
48
+
49
+ def service
50
+ if authenticated?
51
+ @service ||= Amee::Service.new(@auth_token)
52
+ else
53
+ raise Amee::Session::NotAuthenticated.new "Session is not authenticated"
54
+ end
55
+ end
56
+
57
+ # we send the service the HTTP method along with the parser we want to use
58
+ # and the path
59
+ #
60
+ # @param [Symbol] method the HTTP method that we want to use
61
+ # @param [String] parser_name the parser name we want to use
62
+ # @param [String] path
63
+ # @param [Hash] options
64
+ # @param [Boolean] use_auth_token NOTE not using this right now
65
+ def api_call_without_logging(method, parser_name, path, options, use_auth_token =true, &proc)
66
+ result = service.send(method, parser_name, path, options)
67
+ result = yield result if block_given?
68
+ store_resource(path,result, options[:cache]||{}) if method == :get && caching?
69
+ result
70
+ end
71
+
72
+
73
+ # this over long ie bad method is to either get the cache for a api call
74
+ # or actually call the amee api; if the session has expired we will try
75
+ # to get a new one
76
+ def api_call(method, parser_name, path, options ={}, use_auth_token =true, &proc)
77
+ if (cache = @cache[path]) && caching?
78
+ return cache
79
+ else
80
+ attempts = 0
81
+ begin
82
+ if Amee::Config[:logging]
83
+ Amee::Logging.log_amee_api(method, parser_name, path, options) do
84
+ api_call_without_logging(method, parser_name, path, options, use_auth_token =true, &proc)
85
+ end
86
+ else
87
+ api_call_without_logging(method, parser_name, path, options, use_auth_token =true, &proc)
88
+ end
89
+ rescue Amee::Session::Expired
90
+ attempts +=1
91
+ if attempts < 2
92
+ self.authenticate!
93
+ retry
94
+ else
95
+ raise
96
+ end
97
+ end
98
+ end
99
+ end
100
+
101
+ # @return [Amee::DataApi::DataCategory]
102
+ def get_data_category(path, options = {})
103
+ api_call(:get, "data.category", path, options) do |response|
104
+ Amee::DataApi::DataCategory.from_hash(response, self)
105
+ end
106
+ end
107
+
108
+ # @return [Amee::DataApi::DrillDown]
109
+ def drill(path, options = {})
110
+ api_call(:get, "data.drill", "#{path}/drill", :query => options[:selections]) do |response|
111
+ Amee::DataApi::DrillDown.from_hash(response, self)
112
+ end
113
+ end
114
+
115
+ # @return [Amee::DataApi::DataItem]
116
+ def get_data_item(path, options = {})
117
+ api_call(:get, "data.item", path, options) do |response|
118
+ Amee::DataApi::DataItem.from_hash(response, self)
119
+ end
120
+ end
121
+
122
+ # @return [Amee::DataApi::DataItemValue]
123
+ def get_data_item_value(path, options ={})
124
+ api_call(:get, "data.item_value", path, options) do |response|
125
+ Amee::DataApi::DataItemValue.from_hash(response, self)
126
+ end
127
+ end
128
+
129
+ # @return [Amee::ProfileApi::Profile]
130
+ def create_profile
131
+ @cache.clear
132
+ api_call(:post, "create.profile", "/profiles", :query => {:profile => true}) do |response|
133
+ Amee::ProfileApi::Profile.from_hash(response, self)
134
+ end
135
+ end
136
+
137
+ # @return [Amee::ProfileApi::Profile]
138
+ def get_profile(uid)
139
+ api_call(:get, "get.profile", "/profiles/#{uid}") do |response|
140
+ Amee::ProfileApi::Profile.from_hash(response, self)
141
+ end
142
+ end
143
+
144
+ # @return [Amee::ProfileApi::ProfileItem]
145
+ def update_profile_item(path, options = {})
146
+ @cache.clear
147
+ api_call(:put, "profile_item", path, :query => {:representation => options[:representation] || true}.merge(options[:fields])) do |response|
148
+ Amee::ProfileApi::ProfileItem.from_hash(response, self)
149
+ end
150
+ end
151
+
152
+ # @return [String] locaion of the new resource
153
+ def create_profile_item(path, uid, options = {})
154
+ @cache.clear
155
+ api_call(:post, "create.profile_item", path,
156
+ :query => {:dataItemUid => uid}.merge(options[:fields])) do |response|
157
+ location = response.headers["location"]
158
+ location.is_a?(Array) ? location.first : location
159
+ end
160
+ end
161
+
162
+ # does not create a profile object compared to the create version
163
+ # @return [Hash]
164
+ def new_profile
165
+ @cache.clear
166
+ api_call(:post, "create.profile", "/profiles", :query => {:profile => true}) do |response|
167
+ response
168
+ end
169
+ end
170
+
171
+ # @return [Boolean]
172
+ def delete_profile(uid)
173
+ @cache.clear
174
+ api_call(:delete, "delete.profile", "/profiles/#{uid}") do |response|
175
+ true
176
+ end
177
+ end
178
+
179
+ # @return [Boolean]
180
+ def delete_profile_item(path)
181
+ @cache.clear
182
+ api_call(:delete, "delete.profile_item", path) do |response|
183
+ true
184
+ end
185
+ end
186
+
187
+ # @return [Amee::ProfileApi::ProfileCategory]
188
+ def get_profile_category(path, options = {})
189
+ api_call(:get, "profile_category", path, options) do |response|
190
+ Amee::ProfileApi::ProfileCategory.from_hash(response, self)
191
+ end
192
+ end
193
+
194
+ # @return [Amee::ProfileApi::ProfileItem]
195
+ def get_profile_item(path, options = {})
196
+ api_call(:get, "profile_item", path, options) do |response|
197
+ Amee::ProfileApi::ProfileItem.from_hash(response, self)
198
+ end
199
+ end
200
+
201
+ # @return [Array[Amee::Profile]]
202
+ def profiles
203
+ api_call(:get, "profiles", "/profiles") do |response|
204
+ response.map do |profile|
205
+ Amee::ProfileApi::Profile.from_hash(profile, self) unless profile.empty?
206
+ end
207
+ end
208
+ end
209
+
210
+ # @return [Hash]
211
+ def get_raw(path, options = {})
212
+ api_call(:get, "raw", path)
213
+ end
214
+
215
+ # @param [String] path the path of the resource
216
+ # @param [Hash] cache_options this is the cache options
217
+ def store_resource(path, result, cache_options = {})
218
+ @cache.store(path, result, :expires_in => cache_options[:expires_in] || Amee::Config[:expires_in])
219
+ end
220
+
221
+ end
222
+ end
@@ -0,0 +1,11 @@
1
+ module Amee
2
+ module Utils
3
+ class String
4
+ def self.snake_case(string)
5
+ return string.downcase if string =~ /^[A-Z]+$/
6
+ string.gsub(/([A-Z]+)(?=[A-Z][a-z]?)|\B[A-Z]/, '_\&') =~ /_*(.*)/
7
+ return $+.downcase
8
+ end
9
+ end
10
+ end
11
+ end
data/script/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/amee.rb'}"
9
+ puts "Loading amee gem"
10
+ exec "#{irb} #{libs} --simple-prompt"