joshua 0.2.2 → 0.2.4

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.
data/lib/joshua/error.rb DELETED
@@ -1,61 +0,0 @@
1
- class Joshua
2
- class Error < StandardError
3
- end
4
-
5
- RESCUE_FROM = {}
6
-
7
- class << self
8
- # rescue_from CustomError do ...
9
- # for unhandled
10
- # rescue_from :all do
11
- # api.error 500, 'Error happens'
12
- # end
13
- # define handled error code and description
14
- # error :not_found, 'Document not found'
15
- # error 404, 'Document not found'
16
- # in api methods
17
- # error 404
18
- # error :not_found
19
- def rescue_from klass, desc=nil, &block
20
- RESCUE_FROM[klass] = desc || block
21
- end
22
-
23
- # show and render single error in class error format
24
- # usually when API class not found
25
- def error text
26
- out = Response.new nil
27
- out.error text
28
- out.render
29
- end
30
-
31
- def error_print error
32
- return if ENV['RACK_ENV'] == 'test'
33
-
34
- puts
35
- puts 'Joshua error dump'.red
36
- puts '---'
37
- puts '%s: %s' % [error.class, error.message]
38
- puts '---'
39
- puts error.backtrace
40
- puts '---'
41
- end
42
- end
43
-
44
- ###
45
-
46
- def error desc
47
- if err = RESCUE_FROM[desc]
48
- if err.is_a?(Proc)
49
- err.call
50
- else
51
- response.error desc, err
52
- desc = err
53
- end
54
-
55
- return
56
- end
57
-
58
- raise Joshua::Error, desc
59
- end
60
-
61
- end
data/lib/joshua/opts.rb DELETED
@@ -1,216 +0,0 @@
1
- class Joshua
2
- ANNOTATIONS ||= {}
3
- OPTS = {}
4
- PLUGINS = {}
5
- DOCUMENTED = []
6
-
7
- class << self
8
- @@params = Params::Define.new
9
-
10
- def base what
11
- set :opts, :base, what
12
- end
13
-
14
- # if you want to make API DOC public use "documented"
15
- def documented
16
- if self == Joshua
17
- DOCUMENTED.map(&:to_s).sort.map(&:constantize)
18
- else
19
- DOCUMENTED.push self unless DOCUMENTED.include?(self)
20
- end
21
- end
22
-
23
- def api_path
24
- to_s.underscore.sub(/_api$/, '')
25
- end
26
-
27
- # define method annotations
28
- # annotation :unsecure! do
29
- # @is_unsecure = true
30
- # end
31
- # unsecure!
32
- # def login
33
- # ...
34
- def annotation name, &block
35
- ANNOTATIONS[name] = block
36
- self.define_singleton_method name do |*args|
37
- @@params.add_annotation name, args
38
- end
39
- end
40
-
41
- # /api/companies/1/show
42
- def member &block
43
- @method_type = :member
44
- class_exec &block
45
- @method_type = nil
46
- end
47
-
48
- # /api/companies/list?countrty_id=1
49
- def collection &block
50
- @method_type = :collection
51
- class_exec &block
52
- @method_type = nil
53
- end
54
-
55
- # There are multiple ways to create params
56
- # params :name, String, req: true
57
- # params.name!, String
58
- # params do
59
- # name String, required: true
60
- # name! String
61
- # end
62
- # params :label do |value, opts|
63
- # # validate is value a label, return coarced label
64
- # # or raise error with error
65
- # end
66
- def params *args, &block
67
- if name = args.first
68
- if block
69
- # if argument is provided we create a validator
70
- Params::Parse.define name, &block
71
- else
72
- only_in_api_methods!
73
- @@params.send *args
74
- end
75
- elsif block
76
- @@params.instance_eval &block
77
- else
78
- only_in_api_methods!
79
- @@params
80
- end
81
- end
82
-
83
- # api method icon
84
- # you can find great icons at https://boxicons.com/ - export to svg
85
- def icon data
86
- if @method_type
87
- raise ArgumentError.new('Icons cant be added on methods')
88
- else
89
- set :opts, :icon, data
90
- end
91
- end
92
-
93
- # api method description
94
- def desc data
95
- if @method_type
96
- @@params.add_generic :desc, data
97
- else
98
- set :opts, :desc, data
99
- end
100
- end
101
-
102
- # api method detailed description
103
- def detail data
104
- return if data.to_s == ''
105
-
106
- if @method_type
107
- @@params.add_generic :detail, data
108
- else
109
- set :opts, :detail, data
110
- end
111
- end
112
-
113
- # method in available for GET requests as well
114
- def gettable
115
- if @method_type
116
- @@params.add_generic :gettable
117
- else
118
- raise ArgumentError.new('gettable can only be set on methods')
119
- end
120
- end
121
-
122
- # allow methods without @api.bearer token set
123
- def unsafe
124
- if @method_type
125
- @@params.add_generic :unsafe
126
- else
127
- raise ArgumentError.new('Only api methods can be unsafe')
128
- end
129
- end
130
-
131
- # all api methods are secure (require bearer token)
132
- def unsecure
133
-
134
- end
135
-
136
- # block execute before any public method or just some member or collection methods
137
- def before &block
138
- set_callback :before, block
139
- end
140
-
141
- # block execute after any public method or just some member or collection methods
142
- # used to add meta tags to response
143
- def after &block
144
- set_callback :after, block
145
- end
146
-
147
- # simplified module include, masked as plugin
148
- # Joshua.plugin :foo do ...
149
- # Joshua.plugin :foo
150
- def plugin name, &block
151
- if block_given?
152
- # if block given, define a plugin
153
- PLUGINS[name] = block
154
- else
155
- # without a block execute it
156
- blk = PLUGINS[name]
157
- raise ArgumentError.new('Plugin :%s not defined' % name) unless blk
158
- instance_exec &blk
159
- end
160
- end
161
-
162
- def get *args
163
- opts.dig *args
164
- end
165
-
166
- # dig all options for a current class
167
- def opts
168
- out = {}
169
-
170
- # dig down the ancestors tree till Object class
171
- ancestors.each do |klass|
172
- break if klass == Object
173
-
174
- # copy all member and collection method options
175
- keys = (OPTS[klass.to_s] || {}).keys
176
- keys.each do |type|
177
- for k, v in (OPTS.dig(klass.to_s, type) || {})
178
- out[type] ||= {}
179
- out[type][k] ||= v
180
- end
181
- end
182
- end
183
-
184
- out
185
- end
186
-
187
- # here we capture member & collection metods
188
- def method_added name
189
- return if name.to_s.start_with?('_api_')
190
- return unless @method_type
191
-
192
- set @method_type, name, @@params.fetch_and_clear_opts
193
-
194
- alias_method "_api_#{@method_type}_#{name}", name
195
- remove_method name
196
- end
197
-
198
- private
199
-
200
- # generic opts set
201
- # set :foo, :bar, :baz
202
- def set *args
203
- name, value = args.pop(2)
204
- args.unshift to_s
205
- pointer = OPTS
206
-
207
- for el in args
208
- pointer[el] ||= {}
209
- pointer = pointer[el]
210
- end
211
-
212
- pointer[name] = value
213
- end
214
- end
215
- end
216
-
@@ -1,53 +0,0 @@
1
- class Joshua
2
- module Params
3
- class Define
4
- def initialize
5
- @opts = { }
6
- end
7
-
8
- def method_missing name, *args
9
- name = name.to_s
10
-
11
- raise ArgumentError.new('! is not allowed in params') if name.include?('!')
12
-
13
- type, opts = args
14
-
15
- if type.is_a?(Hash)
16
- opts = args.first
17
- type = :string
18
- end
19
-
20
- type = :string if type.nil?
21
-
22
- opts ||= {}
23
- opts[:type] = type.to_s.dasherize.downcase.to_sym
24
-
25
- opts[:required] = true if opts[:required].nil?
26
- opts[:required] = false if name.sub! /\?$/, ''
27
- opts[:required] = false if opts.delete(:optional)
28
-
29
- opts.merge!(type: :boolean, default: false) if opts[:type] == :false
30
- opts.merge!(type: :boolean, default: true) if opts[:type] == :true
31
- opts[:required] = false if opts[:type] == :boolean
32
-
33
- @opts[:params] ||= {}
34
- @opts[:params][name.to_sym] = opts
35
- end
36
-
37
- def fetch_and_clear_opts
38
- @opts
39
- .dup
40
- .tap { @opts = {} }
41
- end
42
-
43
- def add_generic name, value=true
44
- @opts[name] = value
45
- end
46
-
47
- def add_annotation name, data
48
- @opts[:annotations] ||= {}
49
- @opts[:annotations][name] = data
50
- end
51
- end
52
- end
53
- end
@@ -1,56 +0,0 @@
1
- class Joshua
2
- module Params
3
- class Parse
4
- class << self
5
- def define name, &block
6
- define_method 'check_%s' % name do |value, opts|
7
- block.call value, opts || {}
8
- end
9
- end
10
- end
11
-
12
- ###
13
-
14
- # check :boolean, 'on'
15
- def check type, value, opts={}
16
- opts[:required] = true if opts.delete(:req)
17
-
18
- if value.to_s == ''
19
- if !opts[:default].nil?
20
- opts[:default]
21
- elsif opts[:required]
22
- error 'Argument missing'
23
- end
24
- else
25
- m = 'check_%s' % type
26
- hard_error 'Unsupported paramter type: %s' % type unless respond_to?(m)
27
-
28
- if opts[:array]
29
- delimiter = opts[:array].is_a?(TrueClass) ? /\s*[,:;]\s*/ : opts[:array]
30
-
31
- value = value.split(delimiter) unless value.is_a?(Array)
32
- value.map { |_| check_send m, _, opts }
33
- else
34
- check_send m, value, opts
35
- end
36
- end
37
- end
38
-
39
- private
40
-
41
- def check_send m, value, opts
42
- send(m, value, opts).tap do |_|
43
- error 'Value not in range of values' if opts[:values] && !opts[:values].include?(_)
44
- end
45
- end
46
-
47
- def error desc
48
- raise Joshua::Error, desc
49
- end
50
-
51
- def hard_error desc
52
- raise StandardError, desc
53
- end
54
- end
55
- end
56
- end
@@ -1,152 +0,0 @@
1
- require 'date'
2
-
3
- class Joshua
4
- module Params
5
- class Parse
6
- # params.is_active :boolean, default: false
7
- def check_boolean value, opts={}
8
- return false unless value
9
-
10
- if %w(true 1 on).include?(value.to_s)
11
- true
12
- elsif %w(false 0 off).include?(value.to_s)
13
- false
14
- else
15
- error 'Unsupported boolean param value: %s' % value
16
- end
17
- end
18
-
19
- def check_integer value, opts={}
20
- value.to_i.tap do |test|
21
- error localized(:not_integer) if test.to_s != value.to_s
22
- error localized(:min_value) % opts[:min] if opts[:min] && test < opts[:min]
23
- error localized(:max_value) % opts[:max] if opts[:max] && test > opts[:max]
24
- end
25
- end
26
-
27
- def check_string value, opts={}
28
- value
29
- .to_s
30
- .sub(/^\s+/, '')
31
- .sub(/\s+$/, '')
32
- end
33
-
34
- def check_float value, opts={}
35
- value =
36
- if opts[:round]
37
- value.to_f.round(opts[:round])
38
- else
39
- value.to_f
40
- end
41
-
42
- error localized(:min_value) % opts[:min] if opts[:min] && value < opts[:min]
43
- error localized(:max_value) % opts[:max] if opts[:max] && value > opts[:max]
44
-
45
- value
46
- end
47
-
48
- def check_date value, opts={}
49
- date = DateTime.parse(value)
50
- date = DateTime.new(date.year, date.month, date.day)
51
-
52
- check_date_min_max date, opts
53
- end
54
-
55
- def check_date_time value, opts={}
56
- date = DateTime.parse(value)
57
- check_date_min_max date, opts
58
- end
59
-
60
- def check_hash value, opts={}
61
- value = {} unless value.is_a?(Hash)
62
-
63
- if opts[:allow]
64
- for key in value.keys
65
- value.delete(key) unless opts[:allow].include?(key)
66
- end
67
- end
68
-
69
- value
70
- end
71
-
72
- def check_email email, opts={}
73
- error localized(:email_min) unless email.to_s.length > 7
74
- error localized(:email_missing) unless email.include?('@')
75
- email.downcase
76
- end
77
-
78
- def check_url url
79
- error localized(:url_start) unless url =~ /^https?:\/\/./
80
- url
81
- end
82
-
83
- # geolocation point. google maps url will be automaticly converted
84
- # https://www.google.com/maps/@51.5254742,-0.1057319,13z
85
- def check_point value, opts={}
86
- parts = value.split(/\s*,\s*/) unless parts.is_a?(Array)
87
-
88
- error localized(:point_format) unless parts[1]
89
-
90
- for part in parts
91
- error localized(:point_format) unless part.include?('.')
92
- error localized(:point_format) unless part.length > 5
93
- end
94
-
95
- parts.join(',')
96
- end
97
-
98
- def check_oib oib, opts={}
99
- oib = oib.to_s
100
-
101
- return false unless oib.match(/^[0-9]{11}$/)
102
-
103
- control_sum = (0..9).inject(10) do |middle, position|
104
- middle += oib.at(position).to_i
105
- middle %= 10
106
- middle = 10 if middle == 0
107
- middle *= 2
108
- middle %= 11
109
- end
110
-
111
- control_sum = 11 - control_sum
112
- control_sum = 0 if control_sum == 10
113
-
114
- if control_sum == oib.at(10).to_i
115
- oib.to_i
116
- else
117
- error 'Wrong OIB'
118
- end
119
- end
120
-
121
- private
122
-
123
- def check_date_min_max value, opts={}
124
- if min = opts[:min]
125
- min = DateTime.parse(min)
126
- error localized(:min_date) % min if min > value
127
- end
128
-
129
- if max = opts[:max]
130
- max = DateTime.parse(max)
131
- error localized(:max_date) % max if value > max
132
- end
133
-
134
- value
135
- end
136
-
137
- def localized error
138
- locale =
139
- if defined?(Lux)
140
- Lux.current.locale.to_s
141
- elsif defined?(I18n)
142
- I18n.with_locale || I18n.locale
143
- else
144
- :en
145
- end
146
-
147
- pointer = ERRORS[locale.to_sym] || ERRORS[:en]
148
- pointer[error]
149
- end
150
- end
151
- end
152
- end