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,50 @@
1
+ require "amee/data_api/data_item"
2
+ require "amee/data_api/item_definition"
3
+ module Amee
4
+ module DataApi
5
+ class DataCategory
6
+ include Amee::Model
7
+ self.path_prefix = "/data"
8
+
9
+ list_populators :data_categories => {:class => Amee::DataApi::DataCategory},
10
+ :data_items => {:class => Amee::DataApi::DataItem}
11
+ item_populators :item_definition => {:class => Amee::DataApi::ItemDefinition}
12
+
13
+ # essentially the parent category
14
+ attr_accessor :data_category, :pager
15
+
16
+ # we can only drill with a data_category that has data_items
17
+ #
18
+ # @param [Hash] selection of what we wish to drill down
19
+ #
20
+ # @return [Amee::DataApi::Drill] if we can drill down we get a drill object
21
+ # @return [nil] if we cannot drill then nil will be the name of the day
22
+ def drill(selections = {})
23
+ if can_drill?
24
+ session.drill(self.full_path, :selections => selections)
25
+ end
26
+ end
27
+
28
+ def can_drill?
29
+ !data_items.empty?
30
+ end
31
+
32
+
33
+ # lets delagate this one
34
+ def drill_down
35
+ item_definition && item_definition.drill_down
36
+ end
37
+
38
+ def paginate(options = {})
39
+
40
+ end
41
+
42
+ def populate!
43
+ session.api_call(:get, "data.category", self.full_path) do |response|
44
+ populate_from_hash!(response)
45
+ end
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,28 @@
1
+ require "amee/data_api/data_item_value"
2
+ require "amee/data_api/item_definition"
3
+ module Amee
4
+ module DataApi
5
+ class DataItem
6
+ require "amee/data_api/data_category"
7
+ include Amee::Model
8
+ self.path_prefix = "/data"
9
+
10
+
11
+ attr_accessor :start_date, :end_date, :label, :choices, :kg_c_o2_per_k_wh, :source
12
+ list_populators :item_values => {:class => Amee::DataApi::DataItemValue}
13
+ item_populators :data_category => {:class => Amee::DataApi::DataCategory},
14
+ :item_definition => {:class => Amee::DataApi::ItemDefinition}
15
+
16
+ def populate!
17
+ session.api_call(:get, "data.item", self.full_path) do |response|
18
+ populate_from_hash!(response)
19
+ end
20
+ end
21
+
22
+ def kg_co2_per_kwh
23
+ kg_c_o2_per_k_wh
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,13 @@
1
+ require "amee/data_api/item_value_definition"
2
+ module Amee
3
+ module DataApi
4
+ class DataItemValue
5
+ include ::Amee::Model
6
+ self.path_prefix = "/data"
7
+
8
+ attr_accessor :display_name, :description, :value, :display_path, :unit, :per_unit, :data_item
9
+ item_populators :item_value_definition => {:class => Amee::DataApi::ItemValueDefinition}
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,23 @@
1
+ module Amee
2
+ module DataApi
3
+ class DrillDown
4
+ include ::Amee::Model
5
+ self.path_prefix = "/data"
6
+
7
+ # choices are an array of hashes with keys "value" and "name"
8
+ # same for the selections as well
9
+ attr_accessor :choice_name, :choices, :selections
10
+ item_populators :data_category => {:class => Amee::DataApi::DataCategory}
11
+
12
+ def data_item_uid
13
+ if uid_found?
14
+ choices.first["value"]
15
+ end
16
+ end
17
+
18
+ def uid_found?
19
+ choice_name == "uid"
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,11 @@
1
+ module Amee
2
+ module DataApi
3
+ class ItemDefinition
4
+ include ::Amee::Model
5
+ path_prefix = "/data"
6
+
7
+ attr_accessor :drill_down
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ require "amee/data_api/value_definition"
2
+ module Amee
3
+ module DataApi
4
+ class ItemValueDefinition
5
+ include Amee::Model
6
+ self.path_prefix = "/data"
7
+
8
+ attr_accessor :from_profile, :from_data
9
+ item_populators :value_definition => {:class => Amee::DataApi::ValueDefinition}
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ module Amee
2
+ module DataApi
3
+ class ValueDefinition
4
+ include ::Amee::Model
5
+ self.path_prefix = "/data"
6
+
7
+ attr_accessor :value_type, :description
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,43 @@
1
+ # Approach taken from facebookers logging
2
+ # need to really look into what we want from Amee logging
3
+ require 'benchmark'
4
+ module Amee
5
+ @@logger = nil
6
+ def self.logger=(logger)
7
+ @@logger = logger
8
+ end
9
+ def self.logger
10
+ @@logger
11
+ end
12
+
13
+ module Logging
14
+ def self.log_amee_api(method, parser_name, path, options)
15
+ message = method
16
+ dump = format_da_dump(parser_name, path, options)
17
+ if block_given?
18
+ result = nil
19
+ seconds = Benchmark.realtime { result = yield }
20
+ log_info(message, dump, seconds)
21
+ result
22
+ else
23
+ log_info(message, dump)
24
+ nil
25
+ end
26
+ rescue Exception => e
27
+ exception = "#{e.class.name}: #{e.message}: #{dump}"
28
+ log_info(message, exception)
29
+ raise
30
+ end
31
+
32
+ def self.format_da_dump(parser_name, path, options)
33
+ "AMEE: PARSER NAME: #{parser_name} PATH: #{path} OPTIONS: #{options.inspect}"
34
+ end
35
+
36
+ def self.log_info(message, dump, seconds = 0)
37
+ return unless Amee.logger
38
+ log_message = "#{message} (#{seconds}) #{dump}"
39
+ Amee.logger.info(log_message)
40
+ end
41
+
42
+ end
43
+ end
data/lib/amee/model.rb ADDED
@@ -0,0 +1,128 @@
1
+ # Approach taken from facebooker
2
+ module Amee
3
+ module Model
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ base.__send__(:attr_writer, :session)
7
+ base.__send__(:attr_accessor, :path)
8
+ base.__send__(:attr_accessor, :uid)
9
+ base.__send__(:attr_accessor, :name)
10
+ base.__send__(:attr_accessor, :modified)
11
+ base.__send__(:attr_accessor, :created)
12
+ base.__send__(:attr_accessor, :resource_path)
13
+
14
+ base.class_eval do
15
+ class << base; attr_reader :lazy_populators end
16
+ class << base; attr_accessor :path_prefix end
17
+ path_prefix = ""
18
+ end
19
+ end
20
+
21
+ module ClassMethods
22
+
23
+ def from_hash(hash, session = nil)
24
+ instance = new(hash, session)
25
+ yield instance if block_given?
26
+ instance
27
+ end
28
+
29
+ def item_populators(hash)
30
+ @lazy_populators ||= [] << hash.keys
31
+ populator_getters(hash.keys)
32
+ hash.each_pair do |key, value|
33
+
34
+ define_method("#{key}=") do |definition|
35
+ if session && !definition.nil?
36
+ if self.resource_path
37
+ definition["resource_path"] = self.resource_path+"/#{definition["path"]}"
38
+ end
39
+ instance_variable_set("@#{key}", value[:class].new(definition, session))
40
+ end
41
+ end
42
+
43
+ end
44
+ end
45
+
46
+ def list_populators(hash)
47
+ @lazy_populators ||= [] << hash.keys
48
+ populator_getters(hash.keys)
49
+ hash.each_pair do |key, value|
50
+
51
+ define_method("#{key}=") do |list|
52
+ instance_variable_set("@#{key}", list.map do |item|
53
+ if self.resource_path
54
+ item["resource_path"] = self.resource_path+"/#{item["path"]}"
55
+ end
56
+ value[:class].new(item, session)
57
+ end) if session
58
+ end
59
+
60
+ end
61
+ end
62
+
63
+ def populator_getters(pops)
64
+ pops.each do |symbol|
65
+ define_method(symbol) do
66
+ if !populated? && self.resource_path
67
+ populate!
68
+ end
69
+ instance_variable_get("@#{symbol}")
70
+ end
71
+ end
72
+ end
73
+
74
+ end # ClassMethods
75
+
76
+ def session
77
+ @session || (raise "Must bind this object to a Amee session before using")
78
+ end
79
+
80
+ def initialize(hash = {}, session = nil)
81
+ @session = session
82
+ populate_from_hash!(hash)
83
+ end
84
+
85
+ def full_path
86
+ self.class.path_prefix + resource_path
87
+ end
88
+
89
+ def populated?
90
+ @populated && lazy_populators_populated?
91
+ end
92
+
93
+ def populate!
94
+ raise NotImplementError, "#{self.class} included me and has not overriden me"
95
+ end
96
+
97
+ def populate_from_hash!(hash)
98
+ unless hash.nil? || hash.empty?
99
+ populate_paths(hash["resource_path"], hash["path"])
100
+ hash.each do |key, value|
101
+ set_attr_method = "#{Amee::Utils::String.snake_case(key)}="
102
+ if !value.nil? && respond_to?(set_attr_method)
103
+ self.__send__(set_attr_method, value)
104
+ else
105
+ # attempt to set attribute basically
106
+ end
107
+ end
108
+ @populated = true
109
+ end
110
+ end
111
+
112
+ # we want the resource paths populated along with the path
113
+ # before we populate any other attribute as
114
+ # they may use these attributes
115
+ def populate_paths(resource_path, path)
116
+ self.resource_path, self.path = resource_path, path
117
+ end
118
+
119
+ # if the all the lazy populators have been set then
120
+ # we now when are populated!
121
+ def lazy_populators_populated?
122
+ if self.class.lazy_populators
123
+ self.class.lazy_populators.find_all {|pop| !instance_variable_get("@#{pop}").nil?} == self.class.lazy_populators
124
+ end
125
+ end
126
+
127
+ end
128
+ end
@@ -0,0 +1,137 @@
1
+ # Approach taken from facebooker
2
+ module Amee
3
+ class Parser
4
+ def self.parse(method, data)
5
+ parser = Parser::PARSERS[method]
6
+ parser.process(
7
+ data
8
+ )
9
+ end
10
+ end
11
+
12
+ class DataCategory < Parser
13
+ def self.process(data)
14
+ category = data["dataCategory"]
15
+ parent_category = data["dataCategory"]["dataCategory"] if data["dataCategory"]
16
+ pager = {"pager" => data["children"].delete("pager")}
17
+ categories = {"data_categories" => data["children"].delete("dataCategories")}
18
+ data_items = {"data_items" => data["children"]["dataItems"].delete("rows")} if data["children"]["dataItems"]
19
+ category.merge(categories).
20
+ merge(data_items).
21
+ merge(pager).
22
+ merge({"resource_path" => data["path"]})
23
+ end
24
+ end
25
+
26
+ class DataItem < Parser
27
+ def self.process(data)
28
+ data_item = data["dataItem"]
29
+ item_values = {"item_values" => data["dataItem"].delete("itemValues")}
30
+ data_item.merge(item_values).
31
+ merge({"choices" => data["userValueChoices"]["choices"]}).
32
+ merge({"resource_path" => data["path"]})
33
+ end
34
+ end
35
+
36
+ class DataItemValue < Parser
37
+ def self.process(data)
38
+ data_item_value = data["itemValue"]
39
+ data_item_value.merge({"resource_path" => data["path"]})
40
+ end
41
+ end
42
+
43
+ class Drill < Parser
44
+ def self.process(data)
45
+ choices = {"choices", data["choices"].delete("choices")}
46
+ data.merge(choices).merge({"choice_name" => data["choices"].delete("name")})
47
+ end
48
+ end
49
+
50
+ class Profiles < Parser
51
+ def self.process(data)
52
+ data["profiles"]
53
+ end
54
+ end
55
+
56
+ class ProfileCategory < Parser
57
+ def self.process(data)
58
+ profile_categories = {"profile_categories" => data["children"].delete("dataCategories")}
59
+ profile_items = {"profile_items" => data["children"].delete("profileItems")}
60
+ data.merge(profile_items).merge(profile_categories).
61
+ merge({"resource_path" => data["path"]})
62
+ end
63
+ end
64
+
65
+ class ProfileItem < Parser
66
+ def self.process(data)
67
+ data["profileItem"].merge({"resource_path" => data["path"]})
68
+ end
69
+ end
70
+
71
+ class CreateProfile < Parser
72
+ def self.process(data)
73
+ data["profile"].
74
+ merge({"resource_path" => data["path"]})
75
+ end
76
+ end
77
+
78
+ class UpdateProfile < Parser
79
+ def self.process(data)
80
+ data["profile"].
81
+ merge({"resource_path" => data["path"]})
82
+ end
83
+ end
84
+
85
+ class DeleteProfile < Parser
86
+ def self.process(data)
87
+ data
88
+ end
89
+ end
90
+
91
+ class GetProfile < Parser
92
+ def self.process(data)
93
+ categories = {"profile_categories" => data["children"].delete("dataCategories")}
94
+ data["profile"].merge(categories).
95
+ merge({"resource_path" => data["path"]})
96
+ end
97
+ end
98
+
99
+ class CreateProfileItem < Parser
100
+ def self.process(data)
101
+ data
102
+ end
103
+ end
104
+
105
+ class DeleteProfileItem < Parser
106
+ def self.process(data)
107
+ data
108
+ end
109
+ end
110
+
111
+
112
+ class Raw < Parser
113
+ def self.process(data)
114
+ data
115
+ end
116
+ end
117
+
118
+ class Parser
119
+ PARSERS = {
120
+ 'data.category' => DataCategory,
121
+ 'data.item' => DataItem,
122
+ "data.item_value" => DataItemValue,
123
+ "raw" => Raw,
124
+ "profiles" => Profiles,
125
+ "create.profile" =>CreateProfile,
126
+ "update.profile" => UpdateProfile,
127
+ "delete.profile" => DeleteProfile,
128
+ "create.profile_item" => CreateProfileItem,
129
+ "profile_category" => ProfileCategory,
130
+ "profile_item" => ProfileItem,
131
+ "delete.profile_item" => DeleteProfileItem,
132
+ "get.profile" => GetProfile,
133
+ "profile.category" => ProfileCategory,
134
+ "data.drill" => Drill
135
+ }
136
+ end
137
+ end