tlaw 0.0.2 → 0.1.0.pre

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 (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
data/lib/tlaw/version.rb CHANGED
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module TLAW
2
4
  MAJOR = 0
3
- MINOR = 0
4
- PATCH = 2
5
+ MINOR = 1
6
+ PATCH = 0
7
+ PRE = 'pre'
5
8
 
6
- VERSION = [MAJOR, MINOR, PATCH].join('.')
9
+ VERSION = [MAJOR, MINOR, PATCH, PRE].compact.join('.')
7
10
  end
data/tlaw.gemspec CHANGED
@@ -3,14 +3,12 @@ require './lib/tlaw/version'
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'tlaw'
5
5
  s.version = TLAW::VERSION
6
- s.authors = ['Victor Shepelev']
7
- s.email = 'zverok.offline@gmail.com'
6
+ s.authors = ['Victor Shepelev', 'Joel Van Horn']
7
+ s.email = %w[zverok.offline@gmail.com joel@joelvanhorn.com]
8
8
  s.homepage = 'https://github.com/molybdenum-99/tlaw'
9
9
 
10
- s.summary = 'Here would be summary'
11
- s.description = <<-EOF
12
- And here would be description.
13
- EOF
10
+ s.summary = 'The Last API Wrapper: Pragmatic API wrapper framework'
11
+ s.description = %q{TLAW is the last (and only) API wrapper framework you'll ever need for accessing GET-only APIs in a consistent way (think weather, search, economical indicators, geonames and so on).}
14
12
  s.licenses = ['MIT']
15
13
 
16
14
  s.files = `git ls-files`.split($RS).reject do |file|
@@ -24,10 +22,12 @@ Gem::Specification.new do |s|
24
22
  |\.travis.yml
25
23
  )$/x
26
24
  end
27
- s.require_paths = ["lib"]
28
25
 
29
- s.required_ruby_version = '>= 2.1.0'
26
+ s.require_paths = ['lib']
30
27
 
28
+ s.required_ruby_version = '>= 2.3.0'
29
+
30
+ s.add_runtime_dependency 'backports'
31
31
  s.add_runtime_dependency 'faraday'
32
32
  s.add_runtime_dependency 'faraday_middleware'
33
33
  s.add_runtime_dependency 'addressable'
@@ -38,7 +38,7 @@ Gem::Specification.new do |s|
38
38
  s.add_development_dependency 'rubygems-tasks'
39
39
 
40
40
  # Testing
41
- s.add_development_dependency 'rubocop', '>= 0.40'
41
+ s.add_development_dependency 'rubocop'
42
42
  s.add_development_dependency 'rubocop-rspec'
43
43
  s.add_development_dependency 'rspec', '>= 3.5'
44
44
  s.add_development_dependency 'rspec-its', '~> 1'
metadata CHANGED
@@ -1,15 +1,30 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tlaw
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0.pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Shepelev
8
+ - Joel Van Horn
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2017-07-31 00:00:00.000000000 Z
12
+ date: 2018-12-21 00:00:00.000000000 Z
12
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: backports
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
13
28
  - !ruby/object:Gem::Dependency
14
29
  name: faraday
15
30
  requirement: !ruby/object:Gem::Requirement
@@ -100,14 +115,14 @@ dependencies:
100
115
  requirements:
101
116
  - - ">="
102
117
  - !ruby/object:Gem::Version
103
- version: '0.40'
118
+ version: '0'
104
119
  type: :development
105
120
  prerelease: false
106
121
  version_requirements: !ruby/object:Gem::Requirement
107
122
  requirements:
108
123
  - - ">="
109
124
  - !ruby/object:Gem::Version
110
- version: '0.40'
125
+ version: '0'
111
126
  - !ruby/object:Gem::Dependency
112
127
  name: rubocop-rspec
113
128
  requirement: !ruby/object:Gem::Requirement
@@ -234,19 +249,48 @@ dependencies:
234
249
  - - ">="
235
250
  - !ruby/object:Gem::Version
236
251
  version: '0'
237
- description: " And here would be description.\n"
238
- email: zverok.offline@gmail.com
252
+ description: TLAW is the last (and only) API wrapper framework you'll ever need for
253
+ accessing GET-only APIs in a consistent way (think weather, search, economical indicators,
254
+ geonames and so on).
255
+ email:
256
+ - zverok.offline@gmail.com
257
+ - joel@joelvanhorn.com
239
258
  executables: []
240
259
  extensions: []
241
260
  extra_rdoc_files: []
242
261
  files:
243
262
  - ".codeclimate.yml"
244
263
  - ".rubocop_todo.yml"
264
+ - ".ruby-version"
245
265
  - ".yardopts"
246
266
  - CHANGELOG.md
247
267
  - LICENSE.txt
248
268
  - README.md
249
269
  - examples/demo_base.rb
270
+ - examples/experimental/README.md
271
+ - examples/experimental/afterthedeadline.rb
272
+ - examples/experimental/airvisual.rb
273
+ - examples/experimental/apixu.rb
274
+ - examples/experimental/bing_maps.rb
275
+ - examples/experimental/currencylayer.rb
276
+ - examples/experimental/earthquake.rb
277
+ - examples/experimental/freegeoip.rb
278
+ - examples/experimental/geonames.rb
279
+ - examples/experimental/isfdb.rb
280
+ - examples/experimental/musicbrainz.rb
281
+ - examples/experimental/nominatim.rb
282
+ - examples/experimental/omdb.rb
283
+ - examples/experimental/open_exchange_rates.rb
284
+ - examples/experimental/open_route.rb
285
+ - examples/experimental/open_street_map.rb
286
+ - examples/experimental/quandl.rb
287
+ - examples/experimental/reddit.rb
288
+ - examples/experimental/swapi.rb
289
+ - examples/experimental/tmdb.rb
290
+ - examples/experimental/world_bank.rb
291
+ - examples/experimental/world_bank_climate.rb
292
+ - examples/experimental/wunderground.rb
293
+ - examples/experimental/wunderground_demo.rb
250
294
  - examples/forecast_io.rb
251
295
  - examples/forecast_io_demo.rb
252
296
  - examples/giphy.rb
@@ -260,12 +304,18 @@ files:
260
304
  - lib/tlaw/api_path.rb
261
305
  - lib/tlaw/data_table.rb
262
306
  - lib/tlaw/dsl.rb
307
+ - lib/tlaw/dsl/api_builder.rb
308
+ - lib/tlaw/dsl/base_builder.rb
309
+ - lib/tlaw/dsl/endpoint_builder.rb
310
+ - lib/tlaw/dsl/namespace_builder.rb
263
311
  - lib/tlaw/endpoint.rb
312
+ - lib/tlaw/formatting.rb
313
+ - lib/tlaw/formatting/describe.rb
314
+ - lib/tlaw/formatting/inspect.rb
264
315
  - lib/tlaw/namespace.rb
265
316
  - lib/tlaw/param.rb
266
317
  - lib/tlaw/param/type.rb
267
- - lib/tlaw/param_set.rb
268
- - lib/tlaw/response_processor.rb
318
+ - lib/tlaw/response_processors.rb
269
319
  - lib/tlaw/util.rb
270
320
  - lib/tlaw/version.rb
271
321
  - tlaw.gemspec
@@ -281,16 +331,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
281
331
  requirements:
282
332
  - - ">="
283
333
  - !ruby/object:Gem::Version
284
- version: 2.1.0
334
+ version: 2.3.0
285
335
  required_rubygems_version: !ruby/object:Gem::Requirement
286
336
  requirements:
287
- - - ">="
337
+ - - ">"
288
338
  - !ruby/object:Gem::Version
289
- version: '0'
339
+ version: 1.3.1
290
340
  requirements: []
291
341
  rubyforge_project:
292
- rubygems_version: 2.6.10
342
+ rubygems_version: 2.6.14
293
343
  signing_key:
294
344
  specification_version: 4
295
- summary: Here would be summary
345
+ summary: 'The Last API Wrapper: Pragmatic API wrapper framework'
296
346
  test_files: []
@@ -1,111 +0,0 @@
1
- module TLAW
2
- # Represents set of param current API endpoint or namespace have.
3
- # You'll never instantiate it directly, just look at {DSL#param} for
4
- # param creation. But probably you could make use of knowledge of this
5
- # class' API when deep investigating what's going on, like:
6
- #
7
- # ```ruby
8
- # params = api.namespaces[:my_namespace].endpoints[:my_endpoint].param_set
9
- # p [params.count, params.names, params.describe]
10
- # ```
11
- class ParamSet
12
- attr_accessor :parent
13
-
14
- def initialize
15
- @params = {}
16
- end
17
-
18
- def add(name, **opts)
19
- # Not updating parent param, just make sure it exists
20
- return if @parent && @parent.all_params[name]
21
-
22
- @params[name] =
23
- if @params[name]
24
- @params[name].merge(**opts)
25
- else
26
- Param.make(name, **opts)
27
- end
28
- end
29
-
30
- def [](name)
31
- @params[name]
32
- end
33
-
34
- def to_a
35
- @params.values
36
- end
37
-
38
- def to_h
39
- @params
40
- end
41
-
42
- def names
43
- @params.keys
44
- end
45
-
46
- def empty?
47
- @params.empty? && (!@parent || @parent.empty?)
48
- end
49
-
50
- def to_code
51
- ordered.map(&:to_code).join(', ')
52
- end
53
-
54
- def to_hash_code(values = nil)
55
- if values
56
- names.map { |n| "#{n}: #{values[n].inspect}" }.join(', ')
57
- else
58
- names.map { |n| "#{n}: #{n}" }.join(', ')
59
- end
60
- end
61
-
62
- def describe
63
- Util::Description.new(ordered.map(&:describe).join("\n"))
64
- end
65
-
66
- def process(**input)
67
- validate_unknown(input)
68
-
69
- all_params
70
- .map { |name, dfn| [name, dfn, input[name]] }
71
- .tap(&method(:validate_required))
72
- .reject { |*, val| val.nil? }
73
- .map { |_name, dfn, val| [dfn.field, dfn.convert_and_format(val)] }
74
- .to_h
75
- end
76
-
77
- def all_params
78
- (@parent ? @parent.all_params : {}).merge(@params)
79
- end
80
-
81
- def inspect
82
- "#<#{self.class.name} #{names.join(', ')}"\
83
- "#{" (parent=#{parent.inspect})" if parent && !parent.empty?}>"
84
- end
85
-
86
- alias_method :to_s, :inspect
87
-
88
- private
89
-
90
- def validate_unknown(input)
91
- (input.keys - all_params.keys).tap { |unknown|
92
- unknown.empty? or
93
- fail(ArgumentError, "Unknown parameters: #{unknown.join(', ')}")
94
- }
95
- end
96
-
97
- def validate_required(definitions_and_params)
98
- definitions_and_params.each do |name, dfn, val|
99
- dfn.required? && val.nil? and
100
- fail ArgumentError, "Required parameter #{name} is missing"
101
- end
102
- end
103
-
104
- def ordered
105
- @params.values
106
- .partition(&:keyword?).reverse.map { |args|
107
- args.partition(&:required?)
108
- }.flatten
109
- end
110
- end
111
- end
@@ -1,126 +0,0 @@
1
- module TLAW
2
- # @private
3
- # FIXME: everything is awfully dirty here
4
- class ResponseProcessor
5
- class Base
6
- def initialize(&block)
7
- @block = block
8
- end
9
-
10
- def call(hash)
11
- hash.tap(&@block)
12
- end
13
-
14
- def to_proc
15
- method(:call).to_proc
16
- end
17
- end
18
-
19
- class Key < Base
20
- def initialize(key, &block)
21
- @key = key
22
- super(&block)
23
- end
24
-
25
- def call(hash)
26
- return hash unless hash.is_a?(Hash)
27
- hash.keys.grep(@key).inject(hash) do |res, k|
28
- res.merge(k => @block.call(hash[k]))
29
- end
30
- end
31
- end
32
-
33
- class Replace < Base
34
- def call(hash)
35
- @block.call(hash)
36
- end
37
- end
38
-
39
- class Items < Base
40
- def initialize(key, subkey = nil, &block)
41
- @key = key
42
- @item_processor = subkey ? Key.new(subkey, &block) : Base.new(&block)
43
- end
44
-
45
- def call(hash)
46
- return hash unless hash.is_a?(Hash)
47
- hash.keys.grep(@key).inject(hash) do |res, k|
48
- next res unless hash[k].is_a?(Array)
49
- res.merge(k => hash[k].map(&@item_processor))
50
- end
51
- end
52
- end
53
-
54
- attr_reader :post_processors
55
- attr_accessor :parent
56
-
57
- def initialize(post_processors = [])
58
- @post_processors = post_processors
59
- end
60
-
61
- def add_post_processor(key = nil, &block)
62
- @post_processors << (key ? Key.new(key, &block) : Base.new(&block))
63
- end
64
-
65
- def add_replacer(&block)
66
- @post_processors << Replace.new(&block)
67
- end
68
-
69
- def add_item_post_processor(key, subkey = nil, &block)
70
- @post_processors << Items.new(key, subkey, &block)
71
- end
72
-
73
- def process(hash)
74
- flatten(hash).derp(&method(:post_process)).derp(&method(:datablize))
75
- end
76
-
77
- def all_post_processors
78
- [*(parent ? parent.all_post_processors : nil), *@post_processors]
79
- end
80
-
81
- private
82
-
83
- def flatten(value)
84
- case value
85
- when Hash
86
- flatten_hash(value)
87
- when Array
88
- value.map(&method(:flatten))
89
- else
90
- value
91
- end
92
- end
93
-
94
- def flatten_hash(hash)
95
- hash.flat_map { |k, v|
96
- v = flatten(v)
97
- if v.is_a?(Hash)
98
- v.map { |k1, v1| ["#{k}.#{k1}", v1] }
99
- else
100
- [[k, v]]
101
- end
102
- }.reject { |_, v| v.nil? }.to_h
103
- end
104
-
105
- def post_process(hash)
106
- all_post_processors.inject(hash) { |res, processor|
107
- processor.call(res).derp(&method(:flatten))
108
- }
109
- end
110
-
111
- def datablize(value)
112
- case value
113
- when Hash
114
- value.map { |k, v| [k, datablize(v)] }.to_h
115
- when Array
116
- if !value.empty? && value.all? { |el| el.is_a?(Hash) }
117
- DataTable.new(value)
118
- else
119
- value
120
- end
121
- else
122
- value
123
- end
124
- end
125
- end
126
- end