tlaw 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,111 @@
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
@@ -0,0 +1,124 @@
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) && hash.key?(@key)
27
+
28
+ hash.merge(@key => @block.call(hash[@key]))
29
+ end
30
+ end
31
+
32
+ class Replace < Base
33
+ def call(hash)
34
+ hash.derp(&@block)
35
+ end
36
+ end
37
+
38
+ class Items < Base
39
+ def initialize(key, subkey = nil, &block)
40
+ @key = key
41
+ @item_processor = subkey ? Key.new(subkey, &block) : Base.new(&block)
42
+ end
43
+
44
+ def call(hash)
45
+ return hash unless hash.key?(@key)
46
+ return hash unless hash[@key].is_a?(Array)
47
+
48
+ hash.merge(@key => hash[@key].map(&@item_processor))
49
+ end
50
+ end
51
+
52
+ attr_reader :post_processors
53
+ attr_accessor :parent
54
+
55
+ def initialize(post_processors = [])
56
+ @post_processors = post_processors
57
+ end
58
+
59
+ def add_post_processor(key = nil, &block)
60
+ @post_processors << (key ? Key.new(key, &block) : Base.new(&block))
61
+ end
62
+
63
+ def add_replacer(&block)
64
+ @post_processors << Replace.new(&block)
65
+ end
66
+
67
+ def add_item_post_processor(key, subkey = nil, &block)
68
+ @post_processors << Items.new(key, subkey, &block)
69
+ end
70
+
71
+ def process(hash)
72
+ flatten(hash).derp(&method(:post_process)).derp(&method(:datablize))
73
+ end
74
+
75
+ def all_post_processors
76
+ [*(parent ? parent.all_post_processors : nil), *@post_processors]
77
+ end
78
+
79
+ private
80
+
81
+ def flatten(value)
82
+ case value
83
+ when Hash
84
+ flatten_hash(value)
85
+ when Array
86
+ value.map(&method(:flatten))
87
+ else
88
+ value
89
+ end
90
+ end
91
+
92
+ def flatten_hash(hash)
93
+ hash.flat_map { |k, v|
94
+ v = flatten(v)
95
+ if v.is_a?(Hash)
96
+ v.map { |k1, v1| ["#{k}.#{k1}", v1] }
97
+ else
98
+ [[k, v]]
99
+ end
100
+ }.reject { |_, v| v.nil? }.to_h
101
+ end
102
+
103
+ def post_process(hash)
104
+ all_post_processors.inject(hash) { |res, processor|
105
+ processor.call(res).derp(&method(:flatten))
106
+ }
107
+ end
108
+
109
+ def datablize(value)
110
+ case value
111
+ when Hash
112
+ value.map { |k, v| [k, datablize(v)] }.to_h
113
+ when Array
114
+ if !value.empty? && value.all? { |el| el.is_a?(Hash) }
115
+ DataTable.new(value)
116
+ else
117
+ value
118
+ end
119
+ else
120
+ value
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,45 @@
1
+ module TLAW
2
+ module Util
3
+ module_function
4
+
5
+ def camelize(string)
6
+ string
7
+ .sub(/^[a-z\d]*/, &:capitalize)
8
+ .gsub(%r{(?:_|(/))([a-z\d]*)}i) {
9
+ "#{$1}#{$2.capitalize}" # rubocop:disable Style/PerlBackrefs
10
+ }
11
+ end
12
+
13
+ # Description is just a String subclass with rewritten `inspect`
14
+ # implementation (useful in `irb`/`pry`):
15
+ #
16
+ # ```ruby
17
+ # str = "Description of endpoint:\nIt has params:..."
18
+ # # "Description of endpoint:\nIt has params:..."
19
+ #
20
+ # TLAW::Util::Description.new(str)
21
+ # # Description of endpoint:
22
+ # # It has params:...
23
+ # ```
24
+ #
25
+ # TLAW uses it when responds to {APIPath.describe}.
26
+ #
27
+ class Description < String
28
+ alias_method :inspect, :to_s
29
+
30
+ def initialize(str)
31
+ super(str.to_s.gsub(/ +\n/, "\n"))
32
+ end
33
+
34
+ # @private
35
+ def indent(indentation = ' ')
36
+ gsub(/(\A|\n)/, '\1' + indentation)
37
+ end
38
+
39
+ # @private
40
+ def +(other)
41
+ self.class.new(super)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,7 @@
1
+ module TLAW
2
+ MAJOR = 0
3
+ MINOR = 0
4
+ PATCH = 1
5
+
6
+ VERSION = [MAJOR, MINOR, PATCH].join('.')
7
+ end
@@ -0,0 +1,53 @@
1
+ require './lib/tlaw/version'
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'tlaw'
5
+ s.version = TLAW::VERSION
6
+ s.authors = ['Victor Shepelev']
7
+ s.email = 'zverok.offline@gmail.com'
8
+ s.homepage = 'https://github.com/molybdenum-99/tlaw'
9
+
10
+ s.summary = 'Here would be summary'
11
+ s.description = <<-EOF
12
+ And here would be description.
13
+ EOF
14
+ s.licenses = ['MIT']
15
+
16
+ s.files = `git ls-files`.split($RS).reject do |file|
17
+ file =~ /^(?:
18
+ spec\/.*
19
+ |Gemfile
20
+ |Rakefile
21
+ |\.rspec
22
+ |\.gitignore
23
+ |\.rubocop.yml
24
+ |\.travis.yml
25
+ )$/x
26
+ end
27
+ s.require_paths = ["lib"]
28
+
29
+ s.required_ruby_version = '>= 2.1.0'
30
+
31
+ s.add_runtime_dependency 'faraday'
32
+ s.add_runtime_dependency 'addressable'
33
+ s.add_runtime_dependency 'crack'
34
+
35
+ # Managing everything
36
+ s.add_development_dependency 'rake'
37
+ s.add_development_dependency 'rubygems-tasks'
38
+
39
+ # Testing
40
+ s.add_development_dependency 'rubocop', '>= 0.40'
41
+ s.add_development_dependency 'rspec', '>= 3.5'
42
+ s.add_development_dependency 'rspec-its', '~> 1'
43
+ s.add_development_dependency 'simplecov', '~> 0.9'
44
+ s.add_development_dependency 'faker', '>= 1.5'
45
+ s.add_development_dependency 'webmock', '>= 2.1'
46
+
47
+ # Documenting
48
+ s.add_development_dependency 'yard', '>= 0.9.5'
49
+
50
+ # Used in examples/
51
+ s.add_development_dependency 'dotenv'
52
+ s.add_development_dependency 'geo_coord'
53
+ end
metadata ADDED
@@ -0,0 +1,265 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tlaw
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Victor Shepelev
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-09-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: addressable
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: crack
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubygems-tasks
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0.40'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0.40'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '3.5'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '3.5'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec-its
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1'
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.9'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.9'
139
+ - !ruby/object:Gem::Dependency
140
+ name: faker
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '1.5'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '1.5'
153
+ - !ruby/object:Gem::Dependency
154
+ name: webmock
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '2.1'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '2.1'
167
+ - !ruby/object:Gem::Dependency
168
+ name: yard
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: 0.9.5
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: 0.9.5
181
+ - !ruby/object:Gem::Dependency
182
+ name: dotenv
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: geo_coord
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
209
+ description: |2
210
+ And here would be description.
211
+ email: zverok.offline@gmail.com
212
+ executables: []
213
+ extensions: []
214
+ extra_rdoc_files: []
215
+ files:
216
+ - ".codeclimate.yml"
217
+ - ".yardopts"
218
+ - LICENSE.txt
219
+ - README.md
220
+ - examples/demo_base.rb
221
+ - examples/forecast_io.rb
222
+ - examples/forecast_io_demo.rb
223
+ - examples/open_weather_map.rb
224
+ - examples/open_weather_map_demo.rb
225
+ - examples/tmdb_demo.rb
226
+ - examples/urbandictionary_demo.rb
227
+ - lib/tlaw.rb
228
+ - lib/tlaw/api.rb
229
+ - lib/tlaw/api_path.rb
230
+ - lib/tlaw/data_table.rb
231
+ - lib/tlaw/dsl.rb
232
+ - lib/tlaw/endpoint.rb
233
+ - lib/tlaw/namespace.rb
234
+ - lib/tlaw/param.rb
235
+ - lib/tlaw/param/type.rb
236
+ - lib/tlaw/param_set.rb
237
+ - lib/tlaw/response_processor.rb
238
+ - lib/tlaw/util.rb
239
+ - lib/tlaw/version.rb
240
+ - tlaw.gemspec
241
+ homepage: https://github.com/molybdenum-99/tlaw
242
+ licenses:
243
+ - MIT
244
+ metadata: {}
245
+ post_install_message:
246
+ rdoc_options: []
247
+ require_paths:
248
+ - lib
249
+ required_ruby_version: !ruby/object:Gem::Requirement
250
+ requirements:
251
+ - - ">="
252
+ - !ruby/object:Gem::Version
253
+ version: 2.1.0
254
+ required_rubygems_version: !ruby/object:Gem::Requirement
255
+ requirements:
256
+ - - ">="
257
+ - !ruby/object:Gem::Version
258
+ version: '0'
259
+ requirements: []
260
+ rubyforge_project:
261
+ rubygems_version: 2.4.8
262
+ signing_key:
263
+ specification_version: 4
264
+ summary: Here would be summary
265
+ test_files: []