steroids 1.0.0
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.
- checksums.yaml +7 -0
- data/lib/base/class.rb +15 -0
- data/lib/base/error.rb +87 -0
- data/lib/base/hash.rb +49 -0
- data/lib/base/list.rb +51 -0
- data/lib/base/model.rb +34 -0
- data/lib/base/service.rb +104 -0
- data/lib/base/type.rb +102 -0
- data/lib/concern.rb +130 -0
- data/lib/concerns/controller.rb +73 -0
- data/lib/concerns/error.rb +20 -0
- data/lib/concerns/model.rb +9 -0
- data/lib/concerns/serializer.rb +70 -0
- data/lib/errors/bad_request_error.rb +15 -0
- data/lib/errors/conflict_error.rb +15 -0
- data/lib/errors/forbidden_error.rb +15 -0
- data/lib/errors/generic_error.rb +14 -0
- data/lib/errors/internal_server_error.rb +15 -0
- data/lib/errors/not_found_error.rb +15 -0
- data/lib/errors/not_implemented_error.rb +15 -0
- data/lib/errors/unauthorized_error.rb +15 -0
- data/lib/errors/unprocessable_entity_error.rb +15 -0
- metadata +62 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 0d3566aa564b722d7e942f934413dd202fe31fe79af63089f3f3d98f672aa1e2
|
|
4
|
+
data.tar.gz: da5c4c357a4de8c03b57b772c6d23282f04f530a1282729bd8cd8825f84171ce
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: ed66368c3eb9cc84314b6ff2a6e27a41a00f856003fdee7b2198f56442c57b6cacc4961f186830928f1637dc27543e47fd8c13867c37d3e085dd15de4a772c37
|
|
7
|
+
data.tar.gz: c2d8bdc5a6df81fed23da4ac0ad647458e6c2a99b91eea53a6c2c75fabcdd6452c8b028f93cd0db7ff15bf30aa663341f28c6b96fb187f17c220250ce9f96feb
|
data/lib/base/class.rb
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Steroids
|
|
2
|
+
module Base
|
|
3
|
+
class Class
|
|
4
|
+
include Steroids::Concerns::Error
|
|
5
|
+
class << self
|
|
6
|
+
def inherited(subclass)
|
|
7
|
+
instance_variables.each do |var|
|
|
8
|
+
subclass_variable_value = instance_variable_get(var).dup
|
|
9
|
+
subclass.instance_variable_set(var, subclass_variable_value)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
data/lib/base/error.rb
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
module Steroids
|
|
2
|
+
module Base
|
|
3
|
+
class Error < StandardError
|
|
4
|
+
include ActiveModel::Serialization
|
|
5
|
+
|
|
6
|
+
@@DEFAULT_MESSAGE = 'An error has occurred while processing your request [Steroids::Base::Error]'
|
|
7
|
+
|
|
8
|
+
attr_reader :id
|
|
9
|
+
attr_reader :code
|
|
10
|
+
attr_reader :status
|
|
11
|
+
attr_reader :message
|
|
12
|
+
attr_reader :reference
|
|
13
|
+
attr_reader :data
|
|
14
|
+
attr_reader :errors
|
|
15
|
+
attr_reader :key
|
|
16
|
+
attr_reader :proverb
|
|
17
|
+
attr_reader :klass
|
|
18
|
+
|
|
19
|
+
def initialize(status: false, message:, key: nil, errors: nil, data: nil, reference: nil, exception: nil)
|
|
20
|
+
@id = SecureRandom.uuid
|
|
21
|
+
@key = assert_key(key)
|
|
22
|
+
@data = assert_data(data)
|
|
23
|
+
@code = assert_code(status)
|
|
24
|
+
@status = assert_status(status)
|
|
25
|
+
@reference = assert_reference(reference)
|
|
26
|
+
@message = assert_message(exception, message)
|
|
27
|
+
@errors = assert_errors(exception, errors)
|
|
28
|
+
@klass = assert_class(exception)
|
|
29
|
+
@proverb = proverb
|
|
30
|
+
super(@message)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
protected
|
|
34
|
+
|
|
35
|
+
def proverb
|
|
36
|
+
begin
|
|
37
|
+
proverbs = Rails.cache.fetch('core/error_proverbs', expires_in: 1.hour) do
|
|
38
|
+
YAML.load_file(Rails.root.join('config/proverbs.yml'))
|
|
39
|
+
end
|
|
40
|
+
rescue StandardError => e
|
|
41
|
+
Utilities::Logger.push(e)
|
|
42
|
+
proverbs = ['One little bug...']
|
|
43
|
+
end
|
|
44
|
+
proverbs.sample
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def assert_class(exception)
|
|
50
|
+
exception&.class
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def assert_status(status)
|
|
54
|
+
status ? Rack::Utils.status_code(status) : false
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def assert_code(status)
|
|
58
|
+
status ? status.to_s : 'error'
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def assert_data(data)
|
|
62
|
+
data
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def assert_reference(reference)
|
|
66
|
+
reference ? reference.to_s : 'http_error'
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def assert_key(key)
|
|
70
|
+
Array(key)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def assert_errors(exception, errors = [])
|
|
74
|
+
exception_errors = Array(reflect_on_exception(exception, :message))
|
|
75
|
+
(Array(errors) + exception_errors).compact
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def assert_message(exception, message)
|
|
79
|
+
message && message.to_s || @@DEFAULT_MESSAGE
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def reflect_on_exception(exception, attribute)
|
|
83
|
+
exception&.respond_to?(attribute) ? exception.message : nil
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
data/lib/base/hash.rb
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module Steroids
|
|
2
|
+
module Base
|
|
3
|
+
class Hash < Steroids::Base::Class
|
|
4
|
+
#include Enumerable # should implement each
|
|
5
|
+
|
|
6
|
+
attr_accessor :context
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
@context = {}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def add(object = {})
|
|
13
|
+
@context.merge!(object)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def <<(object)
|
|
17
|
+
@context.merge!(object)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def to_json(*_args)
|
|
21
|
+
@context.to_json
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def to_hash
|
|
25
|
+
@context.to_hash
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def merge(object)
|
|
29
|
+
@context.merge(object)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def merge!(object)
|
|
33
|
+
@context.merge!(object)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def include?(key)
|
|
37
|
+
@context.include?(key)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def empty?
|
|
41
|
+
@context.empty?
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def [](key)
|
|
45
|
+
@context[key]
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
data/lib/base/list.rb
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module Steroids
|
|
2
|
+
module Base
|
|
3
|
+
class List < Steroids::Base::Class
|
|
4
|
+
#include Enumerable # should implement each
|
|
5
|
+
|
|
6
|
+
attr_accessor :errors
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
@errors = []
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def add(object = [])
|
|
13
|
+
add_error(object)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def <<(object = [])
|
|
17
|
+
add_error(object)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def to_ary
|
|
21
|
+
@errors
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def to_a
|
|
25
|
+
to_ary
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def any?
|
|
29
|
+
@errors.any?
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def empty?
|
|
33
|
+
@errors.empty?
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def add_error(object = [])
|
|
39
|
+
if object.is_a? ActiveModel::Errors
|
|
40
|
+
formatted = object.to_a.map { |item| item.gsub(/"/, '\'') }
|
|
41
|
+
elsif object.is_a?(Array)
|
|
42
|
+
formatted = object
|
|
43
|
+
elsif object.is_a?(String)
|
|
44
|
+
formatted = [object]
|
|
45
|
+
end
|
|
46
|
+
formatted.each { |item| Utilities::Logger.push(item) }
|
|
47
|
+
@errors.concat(formatted)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
data/lib/base/model.rb
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Steroids
|
|
2
|
+
module Base
|
|
3
|
+
class Model < Steroids::Base::Class
|
|
4
|
+
include ActiveModel::Model
|
|
5
|
+
include ActiveModel::Serialization
|
|
6
|
+
|
|
7
|
+
def attributes
|
|
8
|
+
self.class.attributes || []
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
class << self
|
|
12
|
+
alias native_attr_accessor attr_accessor
|
|
13
|
+
|
|
14
|
+
def attr_accessor(*attr)
|
|
15
|
+
attributes(*attr)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def attributes(*attr)
|
|
19
|
+
@attributes ||= []
|
|
20
|
+
@attributes.concat(attr).uniq
|
|
21
|
+
native_attr_accessor(*attr)
|
|
22
|
+
@attributes
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def attribute(attribute)
|
|
26
|
+
@attributes ||= []
|
|
27
|
+
@attributes << attribute unless @attributes.include?(attribute)
|
|
28
|
+
native_attr_accessor(attribute)
|
|
29
|
+
attr
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
data/lib/base/service.rb
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
module Steroids
|
|
2
|
+
module Base
|
|
3
|
+
class Service < Steroids::Base::Class
|
|
4
|
+
include Steroids::Concerns::Error
|
|
5
|
+
|
|
6
|
+
@@wrap_in_transaction = true
|
|
7
|
+
@@skip_callbacks = false
|
|
8
|
+
|
|
9
|
+
def call(options = {})
|
|
10
|
+
@output = nil
|
|
11
|
+
@force = options[:force] ||= false
|
|
12
|
+
@skip_callbacks = options[:skip_callbacks] || @@skip_callbacks ||= false
|
|
13
|
+
@@wrap_in_transaction ? ActiveRecord::Base.transaction { process_service } : process_service
|
|
14
|
+
ensure!
|
|
15
|
+
@output
|
|
16
|
+
rescue StandardError => e
|
|
17
|
+
ActiveRecord::Rollback
|
|
18
|
+
ensure!
|
|
19
|
+
rescue_output = rescue!(e)
|
|
20
|
+
raise e unless rescue_output
|
|
21
|
+
|
|
22
|
+
Utilities::Logger.push(e)
|
|
23
|
+
rescue_output
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
protected
|
|
27
|
+
|
|
28
|
+
def process
|
|
29
|
+
true
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def ensure!
|
|
33
|
+
true
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def rescue!(_exception)
|
|
37
|
+
false
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def process_service
|
|
43
|
+
run_before_callbacks unless @skip_callbacks
|
|
44
|
+
@output = process
|
|
45
|
+
run_after_callbacks unless @skip_callbacks
|
|
46
|
+
if errors? && !@force
|
|
47
|
+
raise Steroids::Errors::GenericError.new(
|
|
48
|
+
message: 'Oops, something went wrong',
|
|
49
|
+
errors: errors
|
|
50
|
+
)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def exit(message: nil)
|
|
55
|
+
unless @force
|
|
56
|
+
raise Steroids::Errors::InternalServerError.new(
|
|
57
|
+
message: message,
|
|
58
|
+
errors: errors
|
|
59
|
+
)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def drop(message: nil)
|
|
64
|
+
unless @force
|
|
65
|
+
raise Steroids::Errors::BadRequestError.new(
|
|
66
|
+
message: message,
|
|
67
|
+
errors: errors
|
|
68
|
+
)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def run_before_callbacks
|
|
73
|
+
if self.class.before_callbacks.is_a?(Array)
|
|
74
|
+
self.class.before_callbacks.each do |callback|
|
|
75
|
+
send(callback)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def run_after_callbacks
|
|
81
|
+
if self.class.after_callbacks.is_a?(Array)
|
|
82
|
+
self.class.after_callbacks.each do |callback|
|
|
83
|
+
send(callback)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
class << self
|
|
89
|
+
attr_accessor :before_callbacks
|
|
90
|
+
attr_accessor :after_callbacks
|
|
91
|
+
|
|
92
|
+
def before_process(method)
|
|
93
|
+
@before_callbacks ||= []
|
|
94
|
+
@before_callbacks << method
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def after_process(method)
|
|
98
|
+
@after_callbacks ||= []
|
|
99
|
+
@after_callbacks << method
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
data/lib/base/type.rb
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
module Steroids
|
|
2
|
+
module Base
|
|
3
|
+
class Type < Steroids::Base::Model
|
|
4
|
+
def import(_options, _object = {})
|
|
5
|
+
raise Steroids::Errors::InternalServerError.new(
|
|
6
|
+
message: name + ': Import not implemented'
|
|
7
|
+
)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def to_s
|
|
11
|
+
if attributes.present?
|
|
12
|
+
values.to_json
|
|
13
|
+
else
|
|
14
|
+
''
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def values
|
|
19
|
+
hash = {}
|
|
20
|
+
attributes.each do |attribute|
|
|
21
|
+
hash[attribute] = read_attribute_for_serialization(attribute)
|
|
22
|
+
end
|
|
23
|
+
hash
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def validate
|
|
27
|
+
validate_required && super
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def validate!
|
|
31
|
+
validate_required!
|
|
32
|
+
super
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def validate_required
|
|
36
|
+
missing_attributes.empty?
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def validate_required!
|
|
40
|
+
unless validate_required
|
|
41
|
+
raise Steroids::Errors::InternalServerError.new(
|
|
42
|
+
message: self.class.name + ': Missing required attributes ' + missing_attributes.to_s
|
|
43
|
+
)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def missing_attributes
|
|
48
|
+
self.class.missing_attributes_for(values)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
class << self
|
|
52
|
+
def required_attributes
|
|
53
|
+
@required_attributes ||= []
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def requires(attribute, _options = {})
|
|
57
|
+
unless required_attributes.include?(attribute)
|
|
58
|
+
required_attributes << attribute
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def import(options, object)
|
|
63
|
+
instance = new({}, true)
|
|
64
|
+
instance.import(options, object) if options.present?
|
|
65
|
+
instance
|
|
66
|
+
rescue Exception => e
|
|
67
|
+
raise Steroids::Errors::InternalServerError.new(
|
|
68
|
+
exception: e,
|
|
69
|
+
message: 'Import failed'
|
|
70
|
+
)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def missing_attributes_for(payload)
|
|
74
|
+
missing_attributes = []
|
|
75
|
+
required_attributes.each do |attribute|
|
|
76
|
+
unless payload.keys.include?(attribute) && !payload[attribute].nil?
|
|
77
|
+
missing_attributes << attribute
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
missing_attributes
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def validate_required(payload)
|
|
84
|
+
missing_attributes_for(payload).empty?
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def validate_required!(payload)
|
|
88
|
+
unless validate_required(payload)
|
|
89
|
+
raise Steroids::Errors::InternalServerError.new(
|
|
90
|
+
message: name + ': Missing required attributes ' + missing_attributes_for(payload).to_s
|
|
91
|
+
)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def new(options = {}, ignore_required = false)
|
|
96
|
+
validate_required!(options) unless ignore_required
|
|
97
|
+
super(options)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
data/lib/concern.rb
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
module Steroids
|
|
2
|
+
module Concern
|
|
3
|
+
# ----------------------------------------------------------------------- #
|
|
4
|
+
# Multiple Included Blocks Error #
|
|
5
|
+
# ----------------------------------------------------------------------- #
|
|
6
|
+
|
|
7
|
+
class MultipleIncludedBlocks < StandardError #:nodoc:
|
|
8
|
+
def initialize
|
|
9
|
+
super "Cannot define multiple 'included' blocks for a Concern"
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# ----------------------------------------------------------------------- #
|
|
14
|
+
# Extended #
|
|
15
|
+
# ----------------------------------------------------------------------- #
|
|
16
|
+
|
|
17
|
+
def self.extended(base)
|
|
18
|
+
base.instance_variable_set(:@_dependencies, [])
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# ----------------------------------------------------------------------- #
|
|
22
|
+
# Concern: Append features #
|
|
23
|
+
# ----------------------------------------------------------------------- #
|
|
24
|
+
|
|
25
|
+
def get_proxy(base_class, instance, scope)
|
|
26
|
+
_self = self
|
|
27
|
+
proxy_name = "#{base_class.name.gsub('::', '') + SecureRandom.hex + @scope.to_s.classify}Proxy"
|
|
28
|
+
unless _self.const_defined?(proxy_name)
|
|
29
|
+
proxy_class = Class.new base_class do
|
|
30
|
+
self.table_name = base_class.table_name
|
|
31
|
+
|
|
32
|
+
define_method :initialize do |instance|
|
|
33
|
+
super(instance.attributes)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
instance.attributes.each do |key, _attribute|
|
|
37
|
+
define_method key do
|
|
38
|
+
instance.read_attribute(key)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
define_method "#{key}=" do |value|
|
|
42
|
+
instance.write_attribute(key, value)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
native_methods = Class.instance_methods
|
|
47
|
+
active_methods = ActiveRecord::Base.instance_methods
|
|
48
|
+
own_methods = instance_methods - base_class.instance_methods
|
|
49
|
+
|
|
50
|
+
instance_methods.each do |method|
|
|
51
|
+
next unless !native_methods.include?(method) && !own_methods.include?(method) &&
|
|
52
|
+
!active_methods.include?(method) && method != scope
|
|
53
|
+
|
|
54
|
+
define_method method do |*args|
|
|
55
|
+
instance.send(method, *args)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
_self.const_set(proxy_name, proxy_class)
|
|
60
|
+
end
|
|
61
|
+
_self.const_get(proxy_name)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def append_features(base_class)
|
|
65
|
+
_self = self
|
|
66
|
+
if base_class.instance_variable_defined?(:@_dependencies)
|
|
67
|
+
base_class.instance_variable_get(:@_dependencies) << self
|
|
68
|
+
false
|
|
69
|
+
else
|
|
70
|
+
_scope_name = @_scope_name
|
|
71
|
+
_dependencies = @_dependencies
|
|
72
|
+
_included_block = @_included_block
|
|
73
|
+
|
|
74
|
+
# ----------------------------------------------------------------------- #
|
|
75
|
+
# Ruby native concern handlers #
|
|
76
|
+
# ----------------------------------------------------------------------- #
|
|
77
|
+
|
|
78
|
+
return false if base_class < self
|
|
79
|
+
|
|
80
|
+
super
|
|
81
|
+
|
|
82
|
+
# ----------------------------------------------------------------------- #
|
|
83
|
+
# Defining the concern scope as a method #
|
|
84
|
+
# ----------------------------------------------------------------------- #
|
|
85
|
+
|
|
86
|
+
define_method @_scope_name do
|
|
87
|
+
instance = self
|
|
88
|
+
|
|
89
|
+
proxy = _self.get_proxy(base_class, instance, _scope_name)
|
|
90
|
+
|
|
91
|
+
# ----------------------------------------------------------------------- #
|
|
92
|
+
# Proc & Dependency injection #
|
|
93
|
+
# ----------------------------------------------------------------------- #
|
|
94
|
+
|
|
95
|
+
_dependencies.each { |dependency| proxy.include(dependency) }
|
|
96
|
+
if _self.const_defined?(:ClassMethods)
|
|
97
|
+
proxy.extend const_get(:ClassMethods)
|
|
98
|
+
end
|
|
99
|
+
if _self.instance_variable_defined?(:@_included_block)
|
|
100
|
+
proxy.class_eval(&_included_block)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# ----------------------------------------------------------------------- #
|
|
104
|
+
# Rails & Ruby native concern handlers #
|
|
105
|
+
# ----------------------------------------------------------------------- #
|
|
106
|
+
|
|
107
|
+
@proxy ||= proxy.new(instance)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def concern(scope, &block)
|
|
113
|
+
if instance_variable_defined?(:@_included_block)
|
|
114
|
+
if @_included_block.source_location != block.source_location
|
|
115
|
+
raise MultipleIncludedBlocks
|
|
116
|
+
end
|
|
117
|
+
else
|
|
118
|
+
@_scope_name = scope
|
|
119
|
+
@_included_block = block
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def class_methods(&class_methods_module_definition)
|
|
124
|
+
mod = const_defined?(:ClassMethods, false) ?
|
|
125
|
+
const_get(:ClassMethods) :
|
|
126
|
+
const_set(:ClassMethods, Module.new)
|
|
127
|
+
mod.module_eval(&class_methods_module_definition)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
module Steroids
|
|
2
|
+
module Concerns
|
|
3
|
+
module Controller
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
included do
|
|
6
|
+
before_action do
|
|
7
|
+
context.add(params: params)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
protected
|
|
11
|
+
|
|
12
|
+
def respond_with(data, options = {})
|
|
13
|
+
options = __parse_options(data, options)
|
|
14
|
+
data = __apply_scopes(data, options)
|
|
15
|
+
data = __apply_pagination(data, options)
|
|
16
|
+
return __response(data, options)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def context
|
|
20
|
+
@context ||= Steroids::Base::Hash.new
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def __parse_options(data, options)
|
|
26
|
+
options[:serializer] ||= self.class.serializer
|
|
27
|
+
options[:params] = params
|
|
28
|
+
if data.is_a?(Array) || data.is_a?(ActiveRecord::Relation)
|
|
29
|
+
options[:each_serializer] ||= options[:serializer]
|
|
30
|
+
options[:serializer] = ::CollectionSerializer
|
|
31
|
+
end
|
|
32
|
+
options
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def __apply_scopes(data, options)
|
|
36
|
+
if data.is_a?(ActiveRecord::Relation)
|
|
37
|
+
data = apply_scopes(data)
|
|
38
|
+
if options[:scoped_only] == true && current_scopes.empty?
|
|
39
|
+
return []
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
data
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def __apply_pagination(data, options)
|
|
46
|
+
if data.is_a?(ActiveRecord::Relation) && options[:paginate] == true
|
|
47
|
+
return data.page(params[:page] || 1)
|
|
48
|
+
end
|
|
49
|
+
data
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def __response(data, options)
|
|
53
|
+
status = options[:status]
|
|
54
|
+
if data
|
|
55
|
+
options = options.merge({ json: data })
|
|
56
|
+
options = options.merge(@context)
|
|
57
|
+
render(options)
|
|
58
|
+
else
|
|
59
|
+
status ? head(status) : raise(Steroids::Errors::NotFoundError)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
class << self
|
|
64
|
+
attr_accessor :serializer
|
|
65
|
+
|
|
66
|
+
def default_serializer(serializer)
|
|
67
|
+
@serializer = serializer
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Steroids
|
|
2
|
+
module Concerns
|
|
3
|
+
module Error
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
included do
|
|
6
|
+
def errors?
|
|
7
|
+
errors.any?
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def errors
|
|
11
|
+
@errors ||= Steroids::Base::List.new
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class << self
|
|
15
|
+
attr_accessor :errors
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module Steroids
|
|
2
|
+
module Concerns
|
|
3
|
+
module Serializer
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
included do
|
|
6
|
+
def initialize(object, options = {})
|
|
7
|
+
options.each { |name, value| instance_variable_set("@#{name}", value) }
|
|
8
|
+
super(object, options)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def serializable_hash(adapter_options = nil, options = {}, adapter_instance = self.class.serialization_adapter_instance)
|
|
12
|
+
if @object
|
|
13
|
+
hash = super
|
|
14
|
+
hash.each { |key, value| hash.delete(key) if value.nil? }
|
|
15
|
+
hash
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def json_key
|
|
20
|
+
'root'
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
protected
|
|
24
|
+
|
|
25
|
+
def parse_options
|
|
26
|
+
options ||= @instance_options ||= {}
|
|
27
|
+
options[:params]&.each do |key, value|
|
|
28
|
+
begin
|
|
29
|
+
case options[:params][key]
|
|
30
|
+
when 'true'
|
|
31
|
+
options[:params][key] = true
|
|
32
|
+
when 'false'
|
|
33
|
+
options[:params][key] = false
|
|
34
|
+
when /^[-+]?[1-9]([0-9]*)?$/
|
|
35
|
+
options[:params][key] = Integer(value)
|
|
36
|
+
end
|
|
37
|
+
rescue => exception
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
options
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def options
|
|
44
|
+
options ||= parse_options
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def render(data, options = {})
|
|
48
|
+
if options[:serializer]
|
|
49
|
+
klass = Object.const_get(options[:serializer])
|
|
50
|
+
klass.new(data, self.options.merge(options))
|
|
51
|
+
else
|
|
52
|
+
ActiveModel::Serializer.get_serializer_for(data.class.name)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
class << self
|
|
57
|
+
# Awaiting PR: https://github.com/rails-api/active_model_serializers/pull/2145
|
|
58
|
+
# and https://github.com/rails-api/active_model_serializers/pull/2148
|
|
59
|
+
def attributes(*attrs, **options)
|
|
60
|
+
options = options.except(:key)
|
|
61
|
+
attrs = attrs.first if attrs.first.class == Array
|
|
62
|
+
attrs.each do |attr|
|
|
63
|
+
attribute(attr, options)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Steroids
|
|
2
|
+
module Errors
|
|
3
|
+
class BadRequestError < Steroids::Base::Error
|
|
4
|
+
def initialize(options = {})
|
|
5
|
+
options[:message] ||= 'Something went wrong (Bad request)'
|
|
6
|
+
super(
|
|
7
|
+
{
|
|
8
|
+
status: :bad_request,
|
|
9
|
+
key: :bad_request
|
|
10
|
+
}.merge(options)
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Steroids
|
|
2
|
+
module Errors
|
|
3
|
+
class ConflictError < Steroids::Base::Error
|
|
4
|
+
def initialize(options = {})
|
|
5
|
+
options[:message] ||= "Something went wrong (Internal conflict)"
|
|
6
|
+
super(
|
|
7
|
+
{
|
|
8
|
+
status: :conflict,
|
|
9
|
+
key: :conflict
|
|
10
|
+
}.merge(options)
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Steroids
|
|
2
|
+
module Errors
|
|
3
|
+
class ForbiddenError < Steroids::Base::Error
|
|
4
|
+
def initialize(options = {})
|
|
5
|
+
options[:message] ||= "Your request was denied (Forbidden)"
|
|
6
|
+
super(
|
|
7
|
+
{
|
|
8
|
+
status: :forbidden,
|
|
9
|
+
key: :forbidden
|
|
10
|
+
}.merge(options)
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module Steroids
|
|
2
|
+
module Errors
|
|
3
|
+
class GenericError < Steroids::Base::Error
|
|
4
|
+
def initialize(options = {})
|
|
5
|
+
super(
|
|
6
|
+
{
|
|
7
|
+
message: options[:message] || "Something went wrong (Generic error)",
|
|
8
|
+
status: options[:status] ? Rack::Utils.status_code(status) : false
|
|
9
|
+
}.merge(options)
|
|
10
|
+
)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Steroids
|
|
2
|
+
module Errors
|
|
3
|
+
class InternalServerError < Steroids::Base::Error
|
|
4
|
+
def initialize(options = {})
|
|
5
|
+
options[:message] ||= "Something went wrong (Internal error)"
|
|
6
|
+
super(
|
|
7
|
+
{
|
|
8
|
+
status: :internal_server_error,
|
|
9
|
+
key: :server_error
|
|
10
|
+
}.merge(options)
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Steroids
|
|
2
|
+
module Errors
|
|
3
|
+
class NotFoundError < Steroids::Base::Error
|
|
4
|
+
def initialize(options = {})
|
|
5
|
+
super(
|
|
6
|
+
{
|
|
7
|
+
message: options[:message] || "We couldn't find what you were looking for",
|
|
8
|
+
status: :not_found,
|
|
9
|
+
key: :not_found
|
|
10
|
+
}.merge(options)
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Steroids
|
|
2
|
+
module Errors
|
|
3
|
+
class NotImplementedError < Steroids::Base::Error
|
|
4
|
+
def initialize(options = {})
|
|
5
|
+
options[:message] ||= "This feature hasn't been implemented yet"
|
|
6
|
+
super(
|
|
7
|
+
{
|
|
8
|
+
status: :not_implemented,
|
|
9
|
+
key: :not_implemented
|
|
10
|
+
}.merge(options)
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Steroids
|
|
2
|
+
module Errors
|
|
3
|
+
class UnauthorizedError < Steroids::Base::Error
|
|
4
|
+
def initialize(options = {})
|
|
5
|
+
options[:message] ||= 'You shall not pass! (Unauthorized)'
|
|
6
|
+
super(
|
|
7
|
+
{
|
|
8
|
+
status: :unauthorized,
|
|
9
|
+
key: :unauthorized
|
|
10
|
+
}.merge(options)
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Steroids
|
|
2
|
+
module Errors
|
|
3
|
+
class UnprocessableEntityError < Steroids::Base::Error
|
|
4
|
+
def initialize(options = {})
|
|
5
|
+
options[:message] ||= "We couldn't understand your request (Unprocessable entity)"
|
|
6
|
+
super(
|
|
7
|
+
{
|
|
8
|
+
status: :unprocessable_entity,
|
|
9
|
+
key: :unprocessable_entity
|
|
10
|
+
}.merge(options)
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: steroids
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Paul Reboh
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2020-10-20 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: Steroids provides helper for Service-oriented, API based, Rails apps.
|
|
14
|
+
email: dev@bernstein.io
|
|
15
|
+
executables: []
|
|
16
|
+
extensions: []
|
|
17
|
+
extra_rdoc_files: []
|
|
18
|
+
files:
|
|
19
|
+
- lib/base/class.rb
|
|
20
|
+
- lib/base/error.rb
|
|
21
|
+
- lib/base/hash.rb
|
|
22
|
+
- lib/base/list.rb
|
|
23
|
+
- lib/base/model.rb
|
|
24
|
+
- lib/base/service.rb
|
|
25
|
+
- lib/base/type.rb
|
|
26
|
+
- lib/concern.rb
|
|
27
|
+
- lib/concerns/controller.rb
|
|
28
|
+
- lib/concerns/error.rb
|
|
29
|
+
- lib/concerns/model.rb
|
|
30
|
+
- lib/concerns/serializer.rb
|
|
31
|
+
- lib/errors/bad_request_error.rb
|
|
32
|
+
- lib/errors/conflict_error.rb
|
|
33
|
+
- lib/errors/forbidden_error.rb
|
|
34
|
+
- lib/errors/generic_error.rb
|
|
35
|
+
- lib/errors/internal_server_error.rb
|
|
36
|
+
- lib/errors/not_found_error.rb
|
|
37
|
+
- lib/errors/not_implemented_error.rb
|
|
38
|
+
- lib/errors/unauthorized_error.rb
|
|
39
|
+
- lib/errors/unprocessable_entity_error.rb
|
|
40
|
+
homepage: https://github.com/bernstein-io/steroids
|
|
41
|
+
licenses: []
|
|
42
|
+
metadata: {}
|
|
43
|
+
post_install_message:
|
|
44
|
+
rdoc_options: []
|
|
45
|
+
require_paths:
|
|
46
|
+
- lib
|
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
48
|
+
requirements:
|
|
49
|
+
- - ">="
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: '0'
|
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
53
|
+
requirements:
|
|
54
|
+
- - ">="
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: '0'
|
|
57
|
+
requirements: []
|
|
58
|
+
rubygems_version: 3.0.6
|
|
59
|
+
signing_key:
|
|
60
|
+
specification_version: 4
|
|
61
|
+
summary: Steroids - Rails helpers
|
|
62
|
+
test_files: []
|