tlaw 0.0.2 → 0.1.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -0
  3. data/CHANGELOG.md +18 -2
  4. data/README.md +10 -7
  5. data/examples/demo_base.rb +2 -2
  6. data/examples/experimental/README.md +3 -0
  7. data/examples/experimental/afterthedeadline.rb +22 -0
  8. data/examples/experimental/airvisual.rb +14 -0
  9. data/examples/experimental/apixu.rb +32 -0
  10. data/examples/experimental/bing_maps.rb +18 -0
  11. data/examples/experimental/currencylayer.rb +25 -0
  12. data/examples/experimental/earthquake.rb +29 -0
  13. data/examples/experimental/freegeoip.rb +16 -0
  14. data/examples/experimental/geonames.rb +98 -0
  15. data/examples/experimental/isfdb.rb +17 -0
  16. data/examples/experimental/musicbrainz.rb +27 -0
  17. data/examples/experimental/nominatim.rb +52 -0
  18. data/examples/experimental/omdb.rb +68 -0
  19. data/examples/experimental/open_exchange_rates.rb +36 -0
  20. data/examples/experimental/open_route.rb +27 -0
  21. data/examples/experimental/open_street_map.rb +16 -0
  22. data/examples/experimental/quandl.rb +50 -0
  23. data/examples/experimental/reddit.rb +25 -0
  24. data/examples/experimental/swapi.rb +27 -0
  25. data/examples/experimental/tmdb.rb +53 -0
  26. data/examples/experimental/world_bank.rb +85 -0
  27. data/examples/experimental/world_bank_climate.rb +77 -0
  28. data/examples/experimental/wunderground.rb +66 -0
  29. data/examples/experimental/wunderground_demo.rb +7 -0
  30. data/examples/forecast_io.rb +16 -16
  31. data/examples/giphy.rb +4 -4
  32. data/examples/giphy_demo.rb +1 -1
  33. data/examples/open_weather_map.rb +64 -60
  34. data/examples/open_weather_map_demo.rb +4 -4
  35. data/examples/tmdb_demo.rb +1 -1
  36. data/examples/urbandictionary_demo.rb +2 -2
  37. data/lib/tlaw.rb +14 -15
  38. data/lib/tlaw/api.rb +108 -26
  39. data/lib/tlaw/api_path.rb +86 -87
  40. data/lib/tlaw/data_table.rb +15 -10
  41. data/lib/tlaw/dsl.rb +126 -224
  42. data/lib/tlaw/dsl/api_builder.rb +47 -0
  43. data/lib/tlaw/dsl/base_builder.rb +108 -0
  44. data/lib/tlaw/dsl/endpoint_builder.rb +26 -0
  45. data/lib/tlaw/dsl/namespace_builder.rb +86 -0
  46. data/lib/tlaw/endpoint.rb +63 -85
  47. data/lib/tlaw/formatting.rb +55 -0
  48. data/lib/tlaw/formatting/describe.rb +86 -0
  49. data/lib/tlaw/formatting/inspect.rb +52 -0
  50. data/lib/tlaw/namespace.rb +141 -98
  51. data/lib/tlaw/param.rb +45 -141
  52. data/lib/tlaw/param/type.rb +36 -49
  53. data/lib/tlaw/response_processors.rb +81 -0
  54. data/lib/tlaw/util.rb +16 -33
  55. data/lib/tlaw/version.rb +6 -3
  56. data/tlaw.gemspec +9 -9
  57. metadata +63 -13
  58. data/lib/tlaw/param_set.rb +0 -111
  59. data/lib/tlaw/response_processor.rb +0 -126
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 37f3ec860edbe2fac8ea3e85b3e0d2d75392ee15
4
- data.tar.gz: b11a83253074b9dfb89c650bd46b155359f4b3f9
3
+ metadata.gz: '009cee34cd6c91e7fdb5a24914d1b8ffcb7c0639'
4
+ data.tar.gz: ab895dc56817673f6222f930a59fc525ff72fff3
5
5
  SHA512:
6
- metadata.gz: e2ad59fcbebd0f0302dbda95365c6c46f15baf8b9333a0bd78c7720540f62785909d6fb3baa07581dd1a504a70527ec047713150c79239ffdcc7566bfa2ba2a1
7
- data.tar.gz: e4cddec1d3e1074001a71dfd6a3858c7afdc57e11f5129ce35fd99d91d8635102b381c4f33b56edd53a974393c792bbbe1f357cd992b484877c0a84c39348039
6
+ metadata.gz: f5e188083216814e176d0c0161a424f9d124272411c8c15ca54b3ed3f7367d1f62e689c61ec80cc8feb22c2231178638dc1c7f066cac199dd383ab4861bbe754
7
+ data.tar.gz: 78c2c75ba92efde05fdb927198fe4a565da0a5ce53d94dd1142b2592f980edeaca11a9018fe5d2e6ef4bc759a9ee49ffd5f3257b5326ab1b44a3b146744e131f
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.3.0
data/CHANGELOG.md CHANGED
@@ -1,11 +1,27 @@
1
1
  # The Last API Wrapper Changelog
2
2
 
3
- # 0.0.2 (2017-07-31)
3
+ ## 0.1.0.pre (2018-12-21)
4
+
5
+ * `Namespace#children` is an `Array` now, with `Namespace#child_index` being a `Hash` (@marcandre);
6
+ * DSL now can accept strings as a Namespace/Endpoint name (@marcandre);
7
+ * Classes' `.inspect` fixed to match Ruby's conventions (@marcandre);
8
+ * Improved object tree navigation (@marcandre):
9
+ * `APIPath#parent`, `APIPath.parent` (immediate parent class/object);
10
+ * `APIPath#parents`, `APIPath.parents` (parent classes/objects all the way up);
11
+ * `Namespace#traverse` (depth-first children tree enumeration).
12
+ * Lots of refactoring (better call it "rewrite", honestly), internal structure was simplified and
13
+ decoupled, API and DSL was kept the same (I hope).
14
+ * I am really thankful to @marcandre and @joelvh for cleaning up job they've done. Sorry, guys,
15
+ eventually I've rewrote the thing completely :)
16
+ * Added `shared_def`/`use_def` to reuse some common parts of definitions (thanks @marcandre for
17
+ discussion).
18
+
19
+ ## 0.0.2 (2017-07-31)
4
20
 
5
21
  * Codebase modernized and rubocopped;
6
22
  * Support for redirects;
7
23
  * Support for pattern-based (regexp) postprocessors.
8
24
 
9
- # 0.0.1 (2016-09-19)
25
+ ## 0.0.1 (2016-09-19)
10
26
 
11
27
  Initial release.
data/README.md CHANGED
@@ -4,9 +4,9 @@
4
4
  [![Build Status](https://travis-ci.org/molybdenum-99/tlaw.svg?branch=master)](https://travis-ci.org/molybdenum-99/tlaw)
5
5
  [![Coverage Status](https://coveralls.io/repos/molybdenum-99/tlaw/badge.svg?branch=master)](https://coveralls.io/r/molybdenum-99/tlaw?branch=master)
6
6
 
7
- **TLAW** (pronounce it like "tea+love"... or whatever) is the last (and
8
- only) API wrapper framework for _get-only APIes_<sup>[*](#get-only-api)</sup>
9
- (think weather, search, economical indicators, geonames and so on).
7
+ **TLAW** (pronounce it like "tea+love"... or whatever) is the last (and only)
8
+ API wrapper framework you'll ever need for accessing _GET-only APIs_<sup>[*](#get-only-api)</sup>
9
+ in a consistent way (think weather, search, economical indicators, geonames and so on).
10
10
 
11
11
  ## Table Of Contents
12
12
 
@@ -68,6 +68,9 @@ options:
68
68
  TLAW tries to close this gap: provide a base for _breath-easy_ API description
69
69
  which produces solid, fast and reliable wrappers.
70
70
 
71
+ See also a [showcase blog post](http://zverok.github.io/blog/2017-07-31-giphy-tlaw.html) with on-the-fly
72
+ API wrapper building for GIPHY.
73
+
71
74
  ## Usage
72
75
 
73
76
  ### URLs and params description
@@ -88,7 +91,7 @@ class Example < TLAW::API
88
91
  # Method is still e.bar, though.
89
92
 
90
93
  # Now, for params definition:
91
- endpont :movie do
94
+ endpoint :movie do
92
95
  param :id
93
96
  end
94
97
  # Method call would be movie(id: '123')
@@ -299,7 +302,7 @@ post_process_items('foo') {
299
302
 
300
303
  # More realistic examples:
301
304
  post_process('meta.count', &:to_i)
302
- post_process('daily') {
305
+ post_process_items('daily') {
303
306
  post_process('date', &Date.method(:parse))
304
307
  }
305
308
  post_process('auxiliary_value') { nil } # Nil's will be thrown away completely
@@ -311,9 +314,9 @@ See full post-processing features descriptions in
311
314
  #### All at once
312
315
 
313
316
  All described response processing steps are performed in this order:
317
+
314
318
  * parsing and initial flattening of JSON (or XML) hash;
315
- * applying post-processors (and flatten the response after _each_ of
316
- them);
319
+ * applying post-processors (and flatten the response after _each_ of them);
317
320
  * make `DataTable`s from arrays of hashes.
318
321
 
319
322
  ### Documentability
@@ -1,7 +1,7 @@
1
- require 'pp'
1
+ $:.unshift File.expand_path('../../lib', __FILE__)
2
2
 
3
- $:.unshift 'lib'
4
3
  require 'tlaw'
4
+ require 'pp'
5
5
 
6
6
  begin
7
7
  require 'dotenv'
@@ -0,0 +1,3 @@
1
+ This folder contains examples of TLAW usage that may or may not be working.
2
+
3
+ Most of them are semi-ready, some are outdated. The main target of it is having a lot of "real" cases to guide further TLAW design.
@@ -0,0 +1,22 @@
1
+ require 'pp'
2
+
3
+ $:.unshift 'lib'
4
+ require 'tlaw'
5
+
6
+ #http://docs.themoviedb.apiary.io/#reference/movies/movielatest
7
+
8
+ class AfterTheDeadline < TLAW::API
9
+ define do
10
+ base 'http://service.afterthedeadline.com'
11
+
12
+ param :key, required: true
13
+
14
+ endpoint :document, '/checkDocument', xml: true do
15
+ param :data, keyword: false
16
+ end
17
+ end
18
+ end
19
+
20
+ atd = AfterTheDeadline.new(key: 'test-tlaw')
21
+
22
+ pp atd.document("Isn't it cool and cute and awesme? Yepx it is.")['results.error'].to_a
@@ -0,0 +1,14 @@
1
+ require_relative '../demo_base'
2
+
3
+ class AirVisual < TLAW::API
4
+ define do
5
+ base 'http://api.airvisual.com/v1'
6
+ param :key, required: true
7
+
8
+ endpoint :nearest, '/nearest?lat={latitude}&lon={longitude}' do
9
+ end
10
+ end
11
+ end
12
+
13
+ av = AirVisual.new(key: ENV['AIRVISUAL'])
14
+ pp av.nearest(50.004444, 36.231389)
@@ -0,0 +1,32 @@
1
+ require_relative '../demo_base'
2
+
3
+ class APIXU < TLAW::API
4
+ define do
5
+ docs 'https://www.apixu.com/doc/'
6
+
7
+ base 'http://api.apixu.com/v1'
8
+
9
+ param :key, required: true
10
+ param :lang
11
+
12
+ namespace :current, '/current.json' do
13
+ endpoint :city, '?q={city}' do
14
+ param :city, :to_s, required: true
15
+ end
16
+ end
17
+
18
+ namespace :forecast, '/forecast.json' do
19
+ endpoint :city, '?q={city}' do
20
+ param :city, :to_s, required: true
21
+ param :days, :to_i
22
+ param :dt, Date, format: ->(dt) { dt.strftime('%Y-%m-%d') }
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ apixu = APIXU.new(key: ENV['APIXU'], lang: 'uk')
29
+ pp apixu.current.city('Kharkiv')
30
+ #res = apixu.forecast.city('Odesa', days: 10, dt: Date.parse('2017-07-03'))
31
+ #pp res['forecast.forecastday']['day.mintemp_c']
32
+ #pp res['forecast.forecastday']['day.maxtemp_c']
@@ -0,0 +1,18 @@
1
+ require_relative '../demo_base'
2
+
3
+ #http://docs.themoviedb.apiary.io/#reference/movies/movielatest
4
+
5
+ class BingMaps < TLAW::API
6
+ define do
7
+ base 'http://dev.virtualearth.net/REST/v1'
8
+ param :key, required: true
9
+
10
+ namespace :locations, '/Locations' do
11
+ endpoint :query, '?q={q}'
12
+ end
13
+ end
14
+ end
15
+
16
+ maps = BingMaps.new(key: ENV['BING_MAPS'])
17
+
18
+ pp maps.locations.query('Харків, Олексіівська 33а')['resourceSets'].first
@@ -0,0 +1,25 @@
1
+ require_relative '../demo_base'
2
+
3
+ class CurrencyLayer < TLAW::API
4
+ define do
5
+ base 'http://apilayer.net/api/'
6
+
7
+ param :access_key, required: true
8
+
9
+ endpoint :live do
10
+ param :currencies, Array
11
+ end
12
+
13
+ endpoint :historical do
14
+ param :date, :to_date, required: :true, keyword: false, format: ->(d) { d.strftime('%Y-%m-%d') }
15
+ param :currencies, Array
16
+
17
+ post_process 'date', &Date.method(:parse)
18
+ post_process 'timestamp', &Time.method(:at)
19
+ end
20
+ end
21
+ end
22
+
23
+ cur = CurrencyLayer.new(access_key: ENV['CURRENCYLAYER'])
24
+
25
+ pp cur.historical(Date.parse('2016-01-01'), currencies: %w[UAH])
@@ -0,0 +1,29 @@
1
+ require 'pp'
2
+
3
+ $:.unshift 'lib'
4
+ require 'tlaw'
5
+
6
+ class Earthquake < TLAW::API
7
+ define do
8
+ base 'http://earthquake.usgs.gov/fdsnws/event/1'
9
+
10
+ endpoint :count, '/count?format=geojson' do
11
+ param :starttime, Date, format: ->(d) { d.strftime('%Y-%m-%d') }
12
+ param :endtime, Date, format: ->(d) { d.strftime('%Y-%m-%d') }
13
+ end
14
+
15
+ endpoint :query, '/query?format=geojson' do
16
+ param :starttime, Date, format: ->(d) { d.strftime('%Y-%m-%d') }
17
+ param :endtime, Date, format: ->(d) { d.strftime('%Y-%m-%d') }
18
+ param :minmagnitude, :to_i
19
+ end
20
+ end
21
+ end
22
+
23
+
24
+ #/query?format=geojson&starttime=2001-01-01&endtime=2014-01-02
25
+
26
+ e = Earthquake.new
27
+ res = e.query(starttime: Date.parse('2000-01-01'), endtime: Date.parse('2017-01-02'), minmagnitude: 9)
28
+ pp res['features'].count
29
+ pp res['features'].first
@@ -0,0 +1,16 @@
1
+ require 'pp'
2
+
3
+ $:.unshift 'lib'
4
+ require 'tlaw'
5
+
6
+ class FreeGeoIP < TLAW::API
7
+ define do
8
+ base 'http://freegeoip.net/json/'
9
+
10
+ endpoint :here, ''
11
+ endpoint :at, '/{ip}'
12
+ end
13
+ end
14
+
15
+ fgi = FreeGeoIP.new
16
+ pp fgi.here
@@ -0,0 +1,98 @@
1
+ require_relative '../demo_base'
2
+ require 'geo/coord'
3
+
4
+ #http://www.geonames.org/export/web-services.html
5
+ #http://www.geonames.org/export/credits.html
6
+ #http://www.geonames.org/export/ws-overview.html
7
+
8
+ class GeoNames < TLAW::API
9
+ define do
10
+ base 'http://api.geonames.org'
11
+
12
+ param :username, required: true
13
+ param :lang
14
+
15
+ ERROR_CODES = {
16
+ 10 => 'Authorization Exception',
17
+ 11 => 'record does not exist',
18
+ 12 => 'other error',
19
+ 13 => 'database timeout',
20
+ 14 => 'invalid parameter',
21
+ 15 => 'no result found',
22
+ 16 => 'duplicate exception',
23
+ 17 => 'postal code not found',
24
+ 18 => 'daily limit of credits exceeded',
25
+ 19 => 'hourly limit of credits exceeded',
26
+ 20 => 'weekly limit of credits exceeded',
27
+ 21 => 'invalid input',
28
+ 22 => 'server overloaded exception',
29
+ 23 => 'service not implemented',
30
+ }
31
+
32
+ post_process do |response|
33
+ if response['status.value']
34
+ fail "#{ERROR_CODES[response['status.value']]}: #{response['status.message']}"
35
+ end
36
+ end
37
+
38
+ namespace :search, path: '/searchJSON' do
39
+ endpoint :query, path: '?q={q}' do
40
+ param :q, required: true
41
+ param :country #TODO: country=FR&country=GP
42
+ end
43
+
44
+ endpoint :name, path: '?name={name}' do
45
+ param :name, required: true
46
+ end
47
+
48
+ endpoint :name_equals, path: '?name_equals={name}' do
49
+ param :name, required: true
50
+ end
51
+ end
52
+
53
+ namespace :postal_codes, path: '' do
54
+ endpoint :countries, path: '/postalCodeCountryInfoJSON'
55
+ end
56
+
57
+ namespace :near, path: '' do
58
+ param :lat, keyword: false
59
+ param :lng, keyword: false
60
+
61
+ endpoint :ocean, path: '/oceanJSON'
62
+ endpoint :country, path: '/countryCodeJSON'
63
+ endpoint :weather, path: '/findNearByWeatherJSON'
64
+ endpoint :extended, path: '/extendedFindNearby', xml: true do
65
+ post_process_replace { |res| res['geonames.geoname'] }
66
+ end
67
+ end
68
+
69
+ namespace :weather, path: '' do
70
+ endpoint :near, path: '/findNearByWeatherJSON?lat={lat}&lng={lng}'
71
+ end
72
+
73
+ endpoint :earthquakes, path: '/earthquakesJSON' do
74
+ param :north
75
+ param :south
76
+ param :east
77
+ param :west
78
+
79
+ post_process_items 'earthquakes' do
80
+ post_process 'datetime', &Time.method(:parse)
81
+ post_process { |h| h['coord'] = Geo::Coord.new(h['lat'], h['lng']) }
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ gn = GeoNames.new(username: ENV.fetch('GEONAMES'))
88
+
89
+ #pp gn.search.name_equals('Kharkiv')['geonames'].to_a
90
+ #pp gn.postal_codes.countries['geonames'].detect { |r| r['countryName'].include?('Thai') }
91
+ #pp gn.near(50.004444, 36.231389).country
92
+ #pp gn.near(50.004444, 36.231389).ocean
93
+ pp gn.near(50.004444, 36.231389).extended.to_a
94
+ #pp gn.near(50.004444, 36.231389).weather
95
+ #pp gn.weather.near(50.004444, 36.231389)
96
+
97
+ #pp gn.earthquakes(north: 44.1, south: -9.9, east: -22.4, west: 55.2)['earthquakes'].to_a
98
+ # => to worldize!
@@ -0,0 +1,17 @@
1
+ require 'pp'
2
+
3
+ $:.unshift 'lib'
4
+ require 'tlaw'
5
+
6
+ class ISFDB < TLAW::API
7
+ define do
8
+ base 'http://www.isfdb.org/cgi-bin/rest'
9
+
10
+ endpoint :isbn, '/getpub.cgi?{isbn}', xml: true
11
+ end
12
+ end
13
+
14
+ i = ISFDB.new
15
+
16
+ #pp i.isbn('0399137378')["ISFDB.Publications.Publication"].last
17
+ pp i.isbn('038533348X')["ISFDB.Publications.Publication"].to_a
@@ -0,0 +1,27 @@
1
+ require 'pp'
2
+
3
+ $:.unshift 'lib'
4
+ require 'tlaw'
5
+
6
+ class MusicBrainz < TLAW::API
7
+ define do
8
+ base 'http://musicbrainz.org/ws/2'
9
+
10
+ endpoint :area, '/area/{id}?fmt=json'
11
+
12
+ namespace :artist do
13
+ endpoint :area, '?area={area_id}&fmt=json'
14
+ endpoint :get, '/{id}?fmt=json' do
15
+ param :inc, :to_a, format: ->(a) { a.join('+') }
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ mb = MusicBrainz.new
22
+
23
+ #pp mb.area '37572420-4b2c-47e5-bf2b-536c9a50a362'
24
+ #pp mb.artist.area('904768d0-61ca-3c40-93ac-93adc36fef4b')['artists'].first
25
+ res = mb.artist.get('00496bc8-93bf-4284-a3ea-cfd97eb99b2f', inc: %w[recordings releases release-groups works])
26
+ pp res['recordings'].first
27
+ pp res['releases'].first
@@ -0,0 +1,52 @@
1
+ require 'pp'
2
+
3
+ $:.unshift 'lib'
4
+ require 'tlaw'
5
+
6
+ class Nominatim < TLAW::API
7
+ define do
8
+ base 'http://nominatim.openstreetmap.org'
9
+
10
+ param :lang, field: 'accept%2Dlanguage'
11
+
12
+ namespace :search, '/search?format=json' do
13
+ endpoint :query, '' do
14
+ param :query, field: :q, keyword: false
15
+
16
+ param :details, field: :addressdetails, enum: {false => 0, true => 1}
17
+ param :geojson, field: :polygon_geojson, enum: {false => 0, true => 1}
18
+ param :tags, field: :extratags, enum: {false => 0, true => 1}
19
+ param :limit
20
+ end
21
+
22
+ endpoint :address, '' do
23
+ param :city
24
+ param :country
25
+ param :street
26
+ param :postalcode
27
+ param :details, field: :addressdetails, enum: {false => 0, true => 1}
28
+ param :geojson, field: :polygon_geojson, enum: {false => 0, true => 1}
29
+ param :tags, field: :extratags, enum: {false => 0, true => 1}
30
+ end
31
+ end
32
+
33
+ endpoint :geocode, '/reverse?format=json' do
34
+ param :lat, :to_f, keyword: false
35
+ param :lng, :to_f, field: :lon, keyword: false
36
+ end
37
+
38
+ endpoint :lookup, '/lookup?format=json&osm_ids={ids}' do
39
+ param :ids # , splat: true -- TODO
40
+ end
41
+ end
42
+ end
43
+
44
+ n = Nominatim.new(lang: 'en')
45
+
46
+ #pp n.search.address(country: 'Ukraine', city: 'Kharkiv', street: '33a Oleksiivska', details: true, geojson: true, tags: true).first
47
+ # pp n.search.query('New York, Times Square', details: true, tags: true, limit: 1).to_a
48
+ #pp n.geocode(50.0403843, 36.203339684)
49
+ #pp n.search.query('Pharmacy, Kharkiv', details: true, tags: true, limit: 100)['address.pharmacy'].compact
50
+ #pp n.geocode(49.9808, 36.2527)
51
+ # pp n.search.address(country: 'Thailand', city: 'Bangkok', details: true, tags: true).to_a
52
+ pp n.search.query('Oleksiivska 33a, Kharkiv, Ukraine').to_a