eaternet 0.3.11 → 0.3.12

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 11257485cfdcbda82f42ae36c646ebfc9616203d
4
- data.tar.gz: 9f3bbe15c16db1bc73527cbb25aa69c4421ea630
3
+ metadata.gz: cfd0797bd4c249ea732ef25485f7310ee1d9ba74
4
+ data.tar.gz: 84e4914a0375a5c84b1d8a48196a19a4f06053ec
5
5
  SHA512:
6
- metadata.gz: 9bd3634278276974dcecb89c48f1285ff652245dd968d8be8349b7063b853c8acfa6af8c5e7fcea6bb2703c50e4dcd3e2cf993784ff5eff92578f8f327de9e4c
7
- data.tar.gz: 2484a3f65c718bd457b6ee56a6c40bb64aa4326950723ee59198c1b05f52f336bde72f3b1035c246638bb606483023c832a81573d5c0bb48e9ae47e4a47cbbf4
6
+ metadata.gz: 12ba76b4684ae01e31e2b97a8e0b18c6cace0a7cebc381ef4550a8ad13d03784982f8f660064de0f849caac930db81365b65f6d096e77302471deff71d041611
7
+ data.tar.gz: 5b207a3fb1c0520bf9721a156a36dc008ac1abfa3c592ede5a57548a9f6e18ca5024f440fa6664ff86c23a93b3cd1e5d7735419bc6b728f4cf4c4e1a5b0679df
@@ -25,6 +25,7 @@ Gem::Specification.new do |spec|
25
25
  spec.add_development_dependency 'minitest'
26
26
  spec.add_development_dependency 'pry'
27
27
  spec.add_development_dependency 'rake', '~> 10'
28
+ spec.add_development_dependency 'timecop'
28
29
  spec.add_development_dependency 'vcr'
29
30
  spec.add_development_dependency 'webmock'
30
31
 
@@ -1,7 +1,6 @@
1
1
  require 'csv'
2
2
  require 'json'
3
3
  require 'logger'
4
- require 'open-uri'
5
4
  require 'set'
6
5
  require 'tempfile'
7
6
 
@@ -14,8 +13,9 @@ require 'eaternet/loggable'
14
13
  module Eaternet
15
14
  module Agencies
16
15
  # A data source for New York City food service health inspections. It
17
- # retrieves the latest info from the official source and makes it easy
18
- # to work with.
16
+ # retrieves the latest info from
17
+ # [the official source](https://data.cityofnewyork.us/Health/DOHMH-New-York-City-Restaurant-Inspection-Results/xx67-kt59)
18
+ # and makes it easy to work with.
19
19
  #
20
20
  # This library conforms to the
21
21
  # [LIVES 1.0 standard](http://www.yelp.com/healthscores) developed by
@@ -66,7 +66,6 @@ module Eaternet
66
66
  end
67
67
 
68
68
  # @example Compute the average inspection score for NYC.
69
- #
70
69
  # # The library is optimized for memory use at the expense
71
70
  # # of speed. E.g., each call to #inspections will iterate
72
71
  # # through the raw CSV. So here, we first retrieve the
@@ -104,6 +103,7 @@ module Eaternet
104
103
  #
105
104
  # @return [FeedInfo]
106
105
  def feed_info
106
+ # Anyone know a contact email?
107
107
  FeedInfo.new do |fi|
108
108
  fi.feed_date = Date.today
109
109
  fi.feed_version = '1.0'
@@ -233,29 +233,17 @@ module Eaternet
233
233
  .map { |row| block.call(row) }
234
234
  end
235
235
 
236
- def unique(objects)
237
- Set.new(objects)
238
- end
239
-
240
236
  def table_file
241
- if @table_file.nil?
242
- @table_file = Tempfile.new('all.csv.')
243
- Nyc.download_to(@table_file)
244
- end
245
- @table_file
246
- end
247
-
248
- def self.download_to(a_file)
249
- download_via_url(a_file)
237
+ @table_file ||= Nyc.download_via_url
250
238
  end
251
239
 
252
240
  # Fastest method for downloading all data but may be non-standard
253
241
  # for Socrata.
254
- def self.download_via_url(a_file)
255
- a_file.write(open(csv_url).read)
242
+ def self.download_via_url
243
+ Eaternet::Util.download_and_cache(source: csv_url, dest: Tempfile.new('nyc'))
256
244
  end
257
245
 
258
- def csv_url
246
+ def self.csv_url
259
247
  domain = 'data.cityofnewyork.us'
260
248
  dataset = 'xx67-kt59'
261
249
  "https://#{domain}/api/views/#{dataset}/rows.csv?accessType=DOWNLOAD"
@@ -12,6 +12,7 @@ module Eaternet
12
12
  logger = Logger.new(ENV['EATERNET_LOG_FILE'] || $stderr)
13
13
  logger.datetime_format = '%Y-%m-%d %H:%M:%S'
14
14
  logger.progname = 'Eaternet'
15
+ logger.level = Logger::ERROR
15
16
  logger
16
17
  end
17
18
  end
@@ -1,3 +1,4 @@
1
+ require 'base64'
1
2
  require 'open-uri'
2
3
  require 'zip'
3
4
 
@@ -22,12 +23,24 @@ module Eaternet
22
23
  dir
23
24
  end
24
25
 
26
+ # Download a file from the network, caching it for 12 hours.
27
+ #
28
+ # @param [String] source the URL to retrieve
29
+ # @param [String] dest pathname in which to save the file
30
+ def self.download_and_cache(source:, dest:)
31
+ cache_path = generate_cache_path(source)
32
+ download(source: source, dest: cache_path) if expired? cache_path
33
+ FileUtils.cp cache_path, dest
34
+ File.open dest
35
+ end
36
+
25
37
  # Download a file from the network.
26
38
  #
27
39
  # @param [String] source the URL to retrieve
28
40
  # @param [String] dest pathname in which to save the file
41
+ # @return [File] the file
29
42
  def self.download(source:, dest:)
30
- open(dest, 'wb') { |file| file << open(source).read }
43
+ File.open(dest, 'wb') { |file| file << open(source).read }
31
44
  end
32
45
 
33
46
  # Extract a Zip archive.
@@ -56,5 +69,29 @@ module Eaternet
56
69
  return nil if a_string.nil?
57
70
  a_string.strip.gsub(/ +/, ' ')
58
71
  end
72
+
73
+ def self.file_age_in_days(path)
74
+ (Time.now - File.mtime(path)).to_i / 86_400.0
75
+ end
76
+
77
+ #
78
+ # private
79
+ #
80
+
81
+ def self.expired?(cache_path)
82
+ !File.exist?(cache_path) || file_age_in_days(cache_path) > 0.5
83
+ end
84
+
85
+ def self.generate_cache_path(url)
86
+ cache_dir = prepare_cache_dir
87
+ cache_key = Base64.strict_encode64(url)
88
+ File.join(cache_dir, cache_key)
89
+ end
90
+
91
+ def self.prepare_cache_dir
92
+ cache_dir = '/tmp/eaternet'
93
+ `mkdir -p #{cache_dir}`
94
+ cache_dir
95
+ end
59
96
  end
60
97
  end
@@ -1,3 +1,3 @@
1
1
  module Eaternet
2
- VERSION = '0.3.11'
2
+ VERSION = '0.3.12'
3
3
  end
@@ -9,7 +9,7 @@ class LoggableTest < Minitest::Test
9
9
 
10
10
  def test_creates_and_sends_log_messages_to_stderr
11
11
  assert_output(nil, /Border Collie/) do
12
- logger.info('Border Collie')
12
+ logger.error('Border Collie')
13
13
  end
14
14
  end
15
15
  end
@@ -0,0 +1,47 @@
1
+ require 'tempfile'
2
+ require 'test_helper'
3
+ require 'timecop'
4
+
5
+ require 'eaternet/util'
6
+
7
+ class UtilTest < Minitest::Test
8
+
9
+ def setup
10
+ @file_contents = 'This is the file'
11
+ @url = "http://downloadtest.com/file-#{rand(1_000_000)}.txt"
12
+ @file = Tempfile.new('temp')
13
+ stub_request(:get, @url).to_return(body: @file_contents)
14
+ end
15
+
16
+ def download
17
+ Eaternet::Util.download(source: @url, dest: @file)
18
+ end
19
+
20
+ def download_and_cache
21
+ Eaternet::Util.download_and_cache(source: @url, dest: @file)
22
+ end
23
+
24
+ def test_downloads_a_file
25
+ download
26
+ assert_equal @file_contents, `cat #{@file.path}`.strip
27
+ assert_requested :get, @url, times: 1
28
+ end
29
+
30
+ def test_downloads_a_file_with_cache_option
31
+ download_and_cache
32
+ assert_equal @file_contents, `cat #{@file.path}`.strip
33
+ assert_requested :get, @url, times: 1
34
+ end
35
+
36
+ def test_uses_a_file_cache
37
+ (1..3).each { download_and_cache }
38
+ assert_requested :get, @url, times: 1
39
+ end
40
+
41
+ def test_expires_a_cache_file
42
+ thirteen_hours = 13 * 60 * 60
43
+ download_and_cache
44
+ Timecop.freeze(Time.now + thirteen_hours) { download_and_cache }
45
+ assert_requested :get, @url, times: 2
46
+ end
47
+ end
@@ -1,13 +1,14 @@
1
1
  require 'minitest/autorun'
2
2
  require 'pry'
3
+ require 'webmock/minitest'
3
4
  require 'vcr'
4
5
 
5
6
  VCR.configure do |c|
6
7
  c.cassette_library_dir = 'test/vcr_cassettes'
7
8
  c.hook_into :webmock
9
+ c.ignore_hosts 'downloadtest.com'
8
10
  end
9
11
 
10
-
11
12
  #
12
13
  # Testing helpers
13
14
  #
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eaternet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.11
4
+ version: 0.3.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robb Shecter
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '10'
97
+ - !ruby/object:Gem::Dependency
98
+ name: timecop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: vcr
99
113
  requirement: !ruby/object:Gem::Requirement
@@ -194,6 +208,7 @@ files:
194
208
  - test/eaternet/lives_1_0/inspection_test.rb
195
209
  - test/eaternet/lives_1_0/legend_test.rb
196
210
  - test/eaternet/loggable_test.rb
211
+ - test/eaternet/util_test.rb
197
212
  - test/fixtures/morris-park-bake-shop.csv
198
213
  - test/script.rb
199
214
  - test/test_helper.rb
@@ -230,6 +245,7 @@ test_files:
230
245
  - test/eaternet/lives_1_0/inspection_test.rb
231
246
  - test/eaternet/lives_1_0/legend_test.rb
232
247
  - test/eaternet/loggable_test.rb
248
+ - test/eaternet/util_test.rb
233
249
  - test/fixtures/morris-park-bake-shop.csv
234
250
  - test/script.rb
235
251
  - test/test_helper.rb