green-button-data 0.6.0 → 0.7.0

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.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MWE4MjIxNGU3MGY3OGQ3M2Y4ZTc4ZjgwYjJkNmVjYzU3MmFjZTA1Mg==
4
+ NjFhMDE3MzUwYzQ3ZmJhOWE3MThiZmJlM2VlMjZhMGY2MzU5Yzc0Nw==
5
5
  data.tar.gz: !binary |-
6
- NGYxZWY5MzMwY2Y1MDhhOTU0NmVhZTY5MDk2ODlhMWQzYWNhZTMyZg==
6
+ OTE2MWUzNDI1YjRiOTQ0ZWZkZWIxNTQxYzE1YzEyZTQ0YzU2NGFhZA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ZmU1NDQ1NTNjYWYyYWJkMzYzNGNmYTQ2OGExNzQ1YzRlY2UwZDQ2NTAyZjk3
10
- N2ZlNTEyZGM5Zjk3MGI4ZmZkOWI4MTMzZTQ2OTgyYTgyMjkyMjhlNzE5YmRh
11
- OTVlYjI4YTgyNGViNmZmNDQ2ZjEyMjBmNTgzYzY0MzY5MzU0ZjM=
9
+ Y2ZmODJhOWJkNTgwOTc5NWFhOWIyZmU3ZDI1YjFjMjAwNzQ2NDY0NDQyYmY4
10
+ ZTMwZmJjMTAxNzIwYzM0NTA4YWFmYWJlM2U3YjQ3MmRjNGY4NTU1NDRhMTgy
11
+ NjY1MzdlYTdiNGEwOTJhZDdiZWU1MmI1MTI3NjNiZWZlYjA4NDE=
12
12
  data.tar.gz: !binary |-
13
- OWQ1ZTk4MTAzOTEwMjIwMmNkNDM1YThiMGEyMzM5OGQ5NDdjMzkwODgyMjNh
14
- MWUwODdmMjNkNjU0NDlmYzA5MmM1ZGY2ZGNlNzBjZmYzMDlmMGYwMzM4Njcz
15
- ZDhkNjIxMTkzNDY1ZGIyMGNiZTFjN2Q2ZTgwOGZlMzZmN2Q1ZjM=
13
+ YmQyZWQ0ZmRmNDYzNjEzZjg0Mzc0ZGIxNmJmNThlMWIwYjJlMzFhOGFmYjRm
14
+ Zjg4MmFjODhlYzE1ZmJlM2E1YzJmMDU5ZThmNTY1OGY4MmExOTUyMDM4Mjcy
15
+ MzU2MmQ2NjllNjRmMTk1NjBkNzAxNWRiMTgwODk1NDc5MmNjOWI=
@@ -0,0 +1,5 @@
1
+ languages:
2
+ Ruby: true
3
+ exclude_paths:
4
+ - "lib/green-button-data/enumerations/*.rb"
5
+ - "lib/green-button-data/parser/*.rb"
data/.gitignore CHANGED
@@ -1,8 +1,8 @@
1
1
  .bundle
2
2
  .ruby-gemset
3
3
  .ruby-version
4
- Gemfile.lock
5
4
  doc/
6
5
  pkg/
7
6
  rdoc/
8
7
  coverage/
8
+ vendor/
@@ -0,0 +1,100 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ green-button-data (0.6.0)
5
+ faraday (~> 0.9)
6
+ nokogiri (~> 1.6)
7
+ sax-machine (~> 1.3)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ addressable (2.3.8)
13
+ codecov (0.1.0)
14
+ json
15
+ simplecov
16
+ url
17
+ coderay (1.1.0)
18
+ crack (0.4.2)
19
+ safe_yaml (~> 1.0.0)
20
+ diff-lcs (1.2.5)
21
+ docile (1.1.5)
22
+ faraday (0.9.2)
23
+ multipart-post (>= 1.2, < 3)
24
+ ffi (1.9.10)
25
+ formatador (0.2.5)
26
+ guard (2.13.0)
27
+ formatador (>= 0.2.4)
28
+ listen (>= 2.7, <= 4.0)
29
+ lumberjack (~> 1.0)
30
+ nenv (~> 0.1)
31
+ notiffany (~> 0.0)
32
+ pry (>= 0.9.12)
33
+ shellany (~> 0.0)
34
+ thor (>= 0.18.1)
35
+ guard-compat (1.2.1)
36
+ guard-rspec (4.5.0)
37
+ guard (~> 2.1)
38
+ guard-compat (~> 1.1)
39
+ rspec (>= 2.99.0, < 4.0)
40
+ json (1.8.3)
41
+ listen (3.0.3)
42
+ rb-fsevent (>= 0.9.3)
43
+ rb-inotify (>= 0.9)
44
+ lumberjack (1.0.9)
45
+ method_source (0.8.2)
46
+ mini_portile2 (2.1.0)
47
+ multipart-post (2.0.0)
48
+ nenv (0.2.0)
49
+ nokogiri (1.6.8)
50
+ mini_portile2 (~> 2.1.0)
51
+ pkg-config (~> 1.1.7)
52
+ notiffany (0.0.7)
53
+ nenv (~> 0.1)
54
+ shellany (~> 0.0)
55
+ pkg-config (1.1.7)
56
+ pry (0.10.1)
57
+ coderay (~> 1.1.0)
58
+ method_source (~> 0.8.1)
59
+ slop (~> 3.4)
60
+ rb-fsevent (0.9.5)
61
+ rb-inotify (0.9.5)
62
+ ffi (>= 0.5.0)
63
+ rspec (3.3.0)
64
+ rspec-core (~> 3.3.0)
65
+ rspec-expectations (~> 3.3.0)
66
+ rspec-mocks (~> 3.3.0)
67
+ rspec-core (3.3.2)
68
+ rspec-support (~> 3.3.0)
69
+ rspec-expectations (3.3.1)
70
+ diff-lcs (>= 1.2.0, < 2.0)
71
+ rspec-support (~> 3.3.0)
72
+ rspec-mocks (3.3.2)
73
+ diff-lcs (>= 1.2.0, < 2.0)
74
+ rspec-support (~> 3.3.0)
75
+ rspec-support (3.3.0)
76
+ safe_yaml (1.0.4)
77
+ sax-machine (1.3.2)
78
+ shellany (0.0.1)
79
+ simplecov (0.10.0)
80
+ docile (~> 1.1.0)
81
+ json (~> 1.8)
82
+ simplecov-html (~> 0.10.0)
83
+ simplecov-html (0.10.0)
84
+ slop (3.6.0)
85
+ thor (0.19.1)
86
+ url (0.3.2)
87
+ webmock (1.21.0)
88
+ addressable (>= 2.3.6)
89
+ crack (>= 0.3.2)
90
+
91
+ PLATFORMS
92
+ ruby
93
+
94
+ DEPENDENCIES
95
+ codecov
96
+ green-button-data!
97
+ guard (~> 2.13)
98
+ guard-rspec
99
+ rspec (~> 3.0)
100
+ webmock (~> 1.21)
data/README.md CHANGED
@@ -108,8 +108,8 @@ ESPI Green Button Data reference API and the other for Pacific Gas & Electric:
108
108
 
109
109
  ```ruby
110
110
  espi_base_url = "https://services.greenbuttondata.org/DataCustodian/espi/" +
111
- "1_1/resources/"
112
- pge_base_url = "https://api.pge.com/GreenButtonConnect/espi/1_1/resources/"
111
+ "1_1/resource/"
112
+ pge_base_url = "https://api.pge.com/GreenButtonConnect/espi/1_1/resource/"
113
113
 
114
114
  espi_client = GreenButtonData.connect base_url: "https://foo.com" do |client|
115
115
  # Override base_url configuration
@@ -4,7 +4,7 @@ Gem::Specification.new do |s|
4
4
  s.name = 'green-button-data'
5
5
  s.version = GreenButtonData::VERSION
6
6
 
7
- s.authors = ['Andrew Jo']
7
+ s.authors = ['Andrew Jo', 'Orlando Lee']
8
8
  s.email = 'engineering@verdigris.co'
9
9
  s.homepage = 'http://verdigris.co'
10
10
  s.licenses = ['BSD-2-Clause']
@@ -192,6 +192,66 @@ module GreenButtonData
192
192
  )
193
193
  end
194
194
 
195
+ def interval_block_bulk(id = nil, options = {})
196
+ if id.is_a? Hash
197
+ options = id
198
+ id = nil
199
+ end
200
+
201
+ subscription_id = options[:subscription_id]
202
+ bulk_file_id = options[:bulk_file_id]
203
+
204
+ get_resource(
205
+ @configuration.bulk_url(
206
+ subscription_id: subscription_id,
207
+ bulk_file_id: bulk_file_id
208
+ ),
209
+ id,
210
+ IntervalBlock,
211
+ sanitize_options(options)
212
+ )
213
+ end
214
+
215
+ def usage_summary_bulk(id = nil, options = {})
216
+ if id.is_a? Hash
217
+ options = id
218
+ id = nil
219
+ end
220
+
221
+ subscription_id = options[:subscription_id]
222
+ bulk_file_id = options[:bulk_file_id]
223
+
224
+ get_resource(
225
+ @configuration.bulk_url(
226
+ subscription_id: subscription_id,
227
+ bulk_file_id: bulk_file_id
228
+ ),
229
+ id,
230
+ UsageSummary,
231
+ sanitize_options(options)
232
+ )
233
+ end
234
+
235
+ def retail_customer_bulk(id = nil, options = {})
236
+ if id.is_a? Hash
237
+ options = id
238
+ id = nil
239
+ end
240
+
241
+ subscription_id = options[:subscription_id]
242
+ bulk_file_id = options[:bulk_file_id]
243
+
244
+ get_resource(
245
+ @configuration.bulk_url(
246
+ subscription_id: subscription_id,
247
+ bulk_file_id: bulk_file_id
248
+ ),
249
+ id,
250
+ RetailCustomer,
251
+ sanitize_options(options)
252
+ )
253
+ end
254
+
195
255
  private
196
256
 
197
257
  def get_resource(url, id = nil, klazz = nil, options = {})
@@ -214,6 +274,7 @@ module GreenButtonData
214
274
  options.delete(:subscription_id) if options.has_key? :subscription_id
215
275
  options.delete(:usage_point_id) if options.has_key? :usage_point_id
216
276
  options.delete(:usage_summary_id) if options.has_key? :usage_summary_id
277
+ options.delete(:bulk_file_id) if options.has_key? :bulk_file_id
217
278
  options
218
279
  end
219
280
  end
@@ -12,7 +12,8 @@ module GreenButtonData
12
12
  :subscription_path,
13
13
  :usage_point_path,
14
14
  :usage_summary_path,
15
- :retail_customer_path
15
+ :retail_customer_path,
16
+ :bulk_path
16
17
 
17
18
  def application_information_url(id = nil)
18
19
  return build_url @application_information_path, id
@@ -137,6 +138,18 @@ module GreenButtonData
137
138
  end
138
139
  end
139
140
 
141
+ def bulk_url(kwargs = {})
142
+ subscription_id = kwargs[:subscription_id]
143
+ bulk_file_id = kwargs[:bulk_file_id]
144
+
145
+ if subscription_id && bulk_file_id
146
+ bulk_url = build_url(@bulk_path)
147
+ return "#{bulk_url}/#{subscription_id}/#{bulk_file_id}"
148
+ else
149
+ raise ArgumentError.new "Missing required arguments: subscription_id or bulk_file_id"
150
+ end
151
+ end
152
+
140
153
  private
141
154
 
142
155
  def build_url(path, id = nil)
@@ -3,7 +3,7 @@ module GreenButtonData
3
3
  include Fetchable
4
4
  include Utilities
5
5
 
6
- attr_reader :id
6
+ attr_reader :id, :usage_point_id
7
7
  attr_accessor :token
8
8
 
9
9
  def initialize(attributes)
@@ -140,64 +140,83 @@ module GreenButtonData
140
140
  self.name.split('::').last
141
141
  end
142
142
 
143
- def each_entry_content(feed)
144
- entry_content = nil
143
+ def resource_from_url(url)
144
+ # Matches resource name in URL (e.g. ApplicationInformation)
145
+ resource = '([a-zA-Z]+)'
145
146
 
146
- feed.entries.each do |entry|
147
- # Matches resource name in URL (e.g. ApplicationInformation)
148
- resource = '([a-zA-Z]+)'
147
+ # Matches Base 64 encoded resource ID used by PG&E for MeterReading
148
+ # resource identifier
149
+ base64_id = '\w+=*'
150
+
151
+ # Matches numeric ID with thousands separator in commas used for
152
+ # UsageSummary IDs for PG&E endpoints but also matches traditional
153
+ # digits without comma separator
154
+ num_id = '(\d+,*\d*)+'
155
+
156
+ # Matches GUID as the resource ID used mainly by PG&E for
157
+ # ApplicationInformation resource identifier
158
+ guid = '[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}' +
159
+ '-[0-9A-Fa-f]{12}'
160
+
161
+ # Identifier can be any of the above patterns
162
+ identifier = "(#{base64_id}|#{num_id}|#{guid})"
163
+
164
+ /\/(#{resource}|#{resource}\/#{identifier})\/*\z/.match(url)
165
+ end
166
+
167
+ def usage_point_id_from_url(url)
168
+ usage_point = 'UsagePoint\/(.*?)\/'
169
+ /(#{usage_point})/.match(url)
170
+ end
149
171
 
150
- # Matches Base 64 encoded resource ID used by PG&E for MeterReading
151
- # resource identifier
152
- base64_id = '\w+=*'
172
+ def valid_resources
173
+ [
174
+ 'applicationinformation',
175
+ 'authorization',
176
+ 'electricpowerusagesummary',
177
+ 'intervalblock',
178
+ 'localtimeparameters',
179
+ 'readingtype',
180
+ 'usagepoint',
181
+ 'usagesummary',
182
+ 'servicelocation',
183
+ 'customeragreement'
184
+ ]
185
+ end
153
186
 
154
- # Matches numeric ID with thousands separator in commas used for
155
- # UsageSummary IDs for PG&E endpoints but also matches traditional
156
- # digits without comma separator
157
- num_id = '(\d+,*\d*)+'
187
+ def valid_resource?(resource)
188
+ resource.downcase =~ /(#{valid_resources.join('|')})/
189
+ end
158
190
 
159
- # Matches GUID as the resource ID used mainly by PG&E for
160
- # ApplicationInformation resource identifier
161
- guid = '[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}' +
162
- '-[0-9A-Fa-f]{12}'
191
+ def type_match_class?(type)
192
+ class_name_mapping = {
193
+ 'ServiceLocation' => 'RetailCustomer',
194
+ 'CustomerAgreement' => 'RetailCustomer',
195
+ 'ElectricPowerUsageSummary' => 'UsageSummary'
196
+ }
197
+ type == class_name || (class_name_mapping.has_key?(type) && class_name_mapping[type] == class_name)
198
+ end
199
+
200
+ def infer_content_from(entry, resource)
201
+ return nil unless valid_resource? resource
202
+ entry.content.send resource.underscore
203
+ end
163
204
 
164
- # Identifier can be any of the above patterns
165
- identifier = "(#{base64_id}|#{num_id}|#{guid})"
205
+ def each_entry_content(feed)
206
+ entry_content = nil
166
207
 
167
- match_data = /\/(#{resource}|#{resource}\/#{identifier})\/*\z/.
168
- match(entry.self)
208
+ feed.entries.each do |entry|
209
+ match_data = resource_from_url(entry.self)
169
210
 
170
211
  unless match_data.nil?
171
212
  id = match_data[4] || entry.id
172
213
  type = match_data[2] || match_data[3]
214
+ next unless type_match_class?(type)
173
215
 
174
- entry_content = case type.downcase
175
-
176
- when 'applicationinformation'
177
- entry.content.application_information
178
- when 'authorization'
179
- entry.content.authorization
180
- when 'electricpowerusagesummary'
181
- entry.content.electric_power_usage_summary
182
- when 'intervalblock'
183
- entry.content.interval_block
184
- when 'localtimeparameters'
185
- entry.content.local_time_parameters
186
- when 'readingtype'
187
- entry.content.reading_type
188
- when 'usagepoint'
189
- entry.content.usage_point
190
- when 'usagesummary'
191
- entry.content.usage_summary
192
- when 'servicelocation'
193
- entry.content.service_location
194
- when 'customeragreement'
195
- entry.content.customer_agreement
196
- else
197
- nil
198
- end
199
-
200
- yield id, entry_content, entry
216
+ entry_content = infer_content_from entry, type
217
+ match_usage_point_id = usage_point_id_from_url(entry.self)
218
+ usage_point_id = match_usage_point_id[2] unless match_usage_point_id.nil?
219
+ yield id, entry_content, entry, usage_point_id
201
220
  end
202
221
  end
203
222
  end
@@ -205,9 +224,10 @@ module GreenButtonData
205
224
  def populate_models(feed)
206
225
  models = GreenButtonData::ModelCollection.new
207
226
 
208
- each_entry_content feed do |id, content, entry|
227
+ each_entry_content feed do |id, content, entry, usage_point_id|
209
228
  attributes_hash = attributes_to_hash(content)
210
229
  attributes_hash[:id] = id
230
+ attributes_hash[:usage_point_id] = usage_point_id
211
231
 
212
232
  attributes_hash[:related_urls] = construct_related_urls entry
213
233
  models << self.new(attributes_hash)
@@ -3,6 +3,7 @@ module GreenButtonData
3
3
  class CostAdditionalDetailLastPeriod < SummaryMeasurement
4
4
  element :note
5
5
  element :itemKind, class: Integer, as: :item_kind
6
+ element :amount, class: Integer, as: :amount
6
7
 
7
8
  # ESPI Namespacing
8
9
  element :'espi:note', as: :note
@@ -11,6 +12,9 @@ module GreenButtonData
11
12
  # Special case for PG&E generic namespacing
12
13
  element :'ns0:note', as: :note
13
14
  element :'ns0:itemKind', class: Integer, as: :item_kind
15
+
16
+ # Special case for SCE generic namespacing
17
+ element :'ns0:amount', class: Integer, as: :amount
14
18
  end
15
19
  end
16
20
  end
@@ -1,3 +1,3 @@
1
1
  module GreenButtonData
2
- VERSION = '0.6.0'
2
+ VERSION = '0.7.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: green-button-data
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Jo
8
+ - Orlando Lee
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2016-04-08 00:00:00.000000000 Z
12
+ date: 2016-09-29 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: nokogiri
@@ -102,9 +103,11 @@ executables: []
102
103
  extensions: []
103
104
  extra_rdoc_files: []
104
105
  files:
106
+ - .codeclimate.yml
105
107
  - .gitignore
106
108
  - .rspec
107
109
  - Gemfile
110
+ - Gemfile.lock
108
111
  - Guardfile
109
112
  - LICENSE.txt
110
113
  - README.md