warped 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +30 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +240 -0
- data/LICENSE.txt +21 -0
- data/README.md +563 -0
- data/Rakefile +12 -0
- data/lib/generators/warped/install_generator.rb +15 -0
- data/lib/generators/warped/templates/initializer.rb.tt +8 -0
- data/lib/warped/controllers/filterable.rb +141 -0
- data/lib/warped/controllers/pageable.rb +130 -0
- data/lib/warped/controllers/searchable.rb +162 -0
- data/lib/warped/controllers/sortable.rb +115 -0
- data/lib/warped/controllers/tabulatable.rb +91 -0
- data/lib/warped/emails/.keep +0 -0
- data/lib/warped/jobs/base.rb +23 -0
- data/lib/warped/queries/filter.rb +91 -0
- data/lib/warped/queries/paginate.rb +100 -0
- data/lib/warped/queries/search.rb +62 -0
- data/lib/warped/queries/sort.rb +90 -0
- data/lib/warped/railtie.rb +12 -0
- data/lib/warped/services/base.rb +94 -0
- data/lib/warped/version.rb +5 -0
- data/lib/warped.rb +31 -0
- data/sig/warped.rbs +4 -0
- data/warped.gemspec +33 -0
- metadata +108 -0
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "warped/services/base"
|
4
|
+
|
5
|
+
module Warped
|
6
|
+
module Queries
|
7
|
+
##
|
8
|
+
# Filter a scope by a set of conditions
|
9
|
+
#
|
10
|
+
# This class provides a simple interface for filtering a scope by a set of conditions.
|
11
|
+
# The conditions are passed as an array of hashes, where each hash contains the following
|
12
|
+
# keys:
|
13
|
+
# - +relation+: the relation to use for the filter (e.g. "=", ">", "in", etc.)
|
14
|
+
# - +field+: the field to filter by
|
15
|
+
# - +value+: the value to filter by
|
16
|
+
#
|
17
|
+
#
|
18
|
+
# @example Filter a scope by a set of conditions
|
19
|
+
# Warped::Queries::Filter.call(User.all, filter_conditions: [
|
20
|
+
# { relation: "=", field: :first_name, value: "John" },
|
21
|
+
# { relation: ">", field: :age, value: 18 }
|
22
|
+
# ])
|
23
|
+
# # => #<ActiveRecord::Relation [...]>
|
24
|
+
#
|
25
|
+
# @see RELATIONS
|
26
|
+
# To see the list of available relations, check the +RELATIONS+ constant.
|
27
|
+
class Filter
|
28
|
+
RELATIONS = %w[= != > >= < <= between in not_in starts_with ends_with contains is_null is_not_null].freeze
|
29
|
+
|
30
|
+
# @param scope [ActiveRecord::Relation] the scope to filter
|
31
|
+
# @param filter_conditions [Array<Hash>] the conditions to filter by
|
32
|
+
# @return [ActiveRecord::Relation] the filtered scope
|
33
|
+
def self.call(scope, filter_conditions:)
|
34
|
+
new(scope, filter_conditions:).call
|
35
|
+
end
|
36
|
+
|
37
|
+
# @param scope [ActiveRecord::Relation] the scope to filter
|
38
|
+
# @param filter_conditions [Array<Hash>] the conditions to filter by
|
39
|
+
# @return [ActiveRecord::Relation] the filtered scope
|
40
|
+
def initialize(scope, filter_conditions:)
|
41
|
+
super()
|
42
|
+
@scope = scope
|
43
|
+
@filter_conditions = filter_conditions
|
44
|
+
end
|
45
|
+
|
46
|
+
def call
|
47
|
+
filter_conditions.reduce(scope) do |scope, filter_condition|
|
48
|
+
relation = filter_condition[:relation].to_s
|
49
|
+
field = filter_condition[:field]
|
50
|
+
value = filter_condition[:value]
|
51
|
+
|
52
|
+
validate_relation!(relation)
|
53
|
+
filtered_scope(scope, relation, field, value)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
attr_reader :scope, :filter_conditions
|
60
|
+
|
61
|
+
def validate_relation!(relation)
|
62
|
+
return if RELATIONS.include?(relation)
|
63
|
+
|
64
|
+
raise ArgumentError, "relation must be one of: #{RELATIONS.join(", ")}"
|
65
|
+
end
|
66
|
+
|
67
|
+
def filtered_scope(scope, relation, field, value)
|
68
|
+
case relation
|
69
|
+
when "=", "in"
|
70
|
+
scope.where(field => value)
|
71
|
+
when "!=", "not_in"
|
72
|
+
scope.where.not(field => value)
|
73
|
+
when "between"
|
74
|
+
scope.where("#{field} BETWEEN ? AND ?", value.first, value.last)
|
75
|
+
when "starts_with"
|
76
|
+
scope.where("#{field} LIKE ?", "#{value}%")
|
77
|
+
when "ends_with"
|
78
|
+
scope.where("#{field} LIKE ?", "%#{value}")
|
79
|
+
when "contains"
|
80
|
+
scope.where("#{field} LIKE ?", "%#{value}%")
|
81
|
+
when "is_null"
|
82
|
+
scope.where(field => nil)
|
83
|
+
when "is_not_null"
|
84
|
+
scope.where.not(field => nil)
|
85
|
+
else # '>', '>=', '<', '<='
|
86
|
+
scope.where("#{field} #{relation} ?", value)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "warped/services/base"
|
4
|
+
|
5
|
+
module Warped
|
6
|
+
module Queries
|
7
|
+
##
|
8
|
+
# Paginate a scope
|
9
|
+
#
|
10
|
+
# This class provides a way to paginate a scope and return the metadata.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# Warped::Queries::Paginate.call(User.all, page: 2, per_page: 10)
|
14
|
+
# # => [{ total_count: 100, total_pages: 10, next_page: 3, prev_page: 1, page: 2, per_page: 10 }, <ActiveRecord::Relation [...]>]
|
15
|
+
#
|
16
|
+
# @see MAX_PER_PAGE
|
17
|
+
# @see DEFAULT_PER_PAGE
|
18
|
+
# To see the maximum number of records per page and the default number of records per page,
|
19
|
+
# check the +MAX_PER_PAGE+ and +DEFAULT_PER_PAGE+ constants.
|
20
|
+
class Paginate
|
21
|
+
MAX_PER_PAGE = 100
|
22
|
+
DEFAULT_PER_PAGE = 10
|
23
|
+
|
24
|
+
# @param scope [ActiveRecord::Relation] the scope to paginate
|
25
|
+
# @param page [Integer] the page number
|
26
|
+
# @param per_page [Integer] the number of records per page
|
27
|
+
# @return [Array<Hash, ActiveRecord::Relation>] the metadata and the paginated scope
|
28
|
+
def self.call(scope, page: nil, per_page: nil)
|
29
|
+
new(scope, page:, per_page:).call
|
30
|
+
end
|
31
|
+
|
32
|
+
# @param scope [ActiveRecord::Relation] the scope to paginate
|
33
|
+
# @param page [Integer] the page number
|
34
|
+
# @param per_page [Integer] the number of records per page
|
35
|
+
# @return [Array<Hash, ActiveRecord::Relation>] the metadata and the paginated scope
|
36
|
+
def initialize(scope, page: nil, per_page: nil)
|
37
|
+
super()
|
38
|
+
@scope = scope
|
39
|
+
@page = page
|
40
|
+
@per_page = per_page
|
41
|
+
end
|
42
|
+
|
43
|
+
def call
|
44
|
+
offset = (page - 1) * per_page
|
45
|
+
paginated_scope = scope.limit(per_page).offset(offset)
|
46
|
+
|
47
|
+
[metadata(scope), paginated_scope]
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
attr_reader :scope
|
53
|
+
|
54
|
+
def page
|
55
|
+
@page.present? ? @page.to_i : 1
|
56
|
+
end
|
57
|
+
|
58
|
+
def per_page
|
59
|
+
@per_page.present? ? [@per_page.to_i, MAX_PER_PAGE].min : DEFAULT_PER_PAGE
|
60
|
+
end
|
61
|
+
|
62
|
+
def collection_count(scope)
|
63
|
+
if scope.group_values.empty?
|
64
|
+
scope.count(:all)
|
65
|
+
else
|
66
|
+
sql = Arel.star.count.over(Arel::Nodes::Grouping.new([]))
|
67
|
+
scope.unscope(:order).pick(sql).to_i
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def metadata(scope)
|
72
|
+
total_count = collection_count(scope)
|
73
|
+
total_pages = pages(total_count, per_page)
|
74
|
+
next_page = next_page(page, total_pages)
|
75
|
+
prev_page = prev_page(page)
|
76
|
+
|
77
|
+
{
|
78
|
+
total_count:,
|
79
|
+
total_pages:,
|
80
|
+
next_page:,
|
81
|
+
prev_page:,
|
82
|
+
page:,
|
83
|
+
per_page:
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
def pages(count, per_page)
|
88
|
+
(count.to_f / per_page).ceil
|
89
|
+
end
|
90
|
+
|
91
|
+
def next_page(page, pages)
|
92
|
+
page < pages ? page + 1 : nil
|
93
|
+
end
|
94
|
+
|
95
|
+
def prev_page(page)
|
96
|
+
page > 1 ? page - 1 : nil
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "warped/services/base"
|
4
|
+
|
5
|
+
module Warped
|
6
|
+
module Queries
|
7
|
+
##
|
8
|
+
# Search for records in a scope
|
9
|
+
#
|
10
|
+
# This class provides a way to search for records in a scope.
|
11
|
+
# It uses a scope in the model to perform the search.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# Warped::Queries::Search.call(User.all, search_term: "John")
|
15
|
+
# # => #<ActiveRecord::Relation [...]>
|
16
|
+
#
|
17
|
+
# By default, it uses the +search+ scope in the model to perform the search.
|
18
|
+
# You can also specify a different scope to use for searching, like so:
|
19
|
+
# @example
|
20
|
+
# Warped::Queries::Search.call(User.all, search_term: "John", model_search_scope: :search_by_name)
|
21
|
+
# # => #<ActiveRecord::Relation [...]>
|
22
|
+
#
|
23
|
+
class Search
|
24
|
+
# @param scope [ActiveRecord::Relation] the scope to search in
|
25
|
+
# @param search_term [String] the term to search for
|
26
|
+
# @param model_search_scope [String, Symbol] the name of the scope to use for searching in the model
|
27
|
+
# @return [ActiveRecord::Relation] the searched scope
|
28
|
+
def self.call(scope, search_term:, model_search_scope: :search)
|
29
|
+
new(scope, search_term:, model_search_scope:).call
|
30
|
+
end
|
31
|
+
|
32
|
+
# @param scope [ActiveRecord::Relation] the scope to search in
|
33
|
+
# @param search_term [String] the term to search for
|
34
|
+
# @param model_search_scope [String, Symbol] the name of the scope to use for searching in the model
|
35
|
+
# @return [ActiveRecord::Relation] the searched scope
|
36
|
+
def initialize(scope, search_term:, model_search_scope: :search)
|
37
|
+
super()
|
38
|
+
@scope = scope
|
39
|
+
@search_term = search_term
|
40
|
+
@model_search_scope = model_search_scope
|
41
|
+
end
|
42
|
+
|
43
|
+
def call
|
44
|
+
return scope if search_term.blank?
|
45
|
+
|
46
|
+
validate_model_search_scope!
|
47
|
+
|
48
|
+
scope.public_send(model_search_scope, search_term)
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
attr_reader :scope, :search_term, :model_search_scope
|
54
|
+
|
55
|
+
def validate_model_search_scope!
|
56
|
+
return if scope.respond_to?(model_search_scope)
|
57
|
+
|
58
|
+
raise ArgumentError, "#{scope.klass} does not respond to #{model_search_scope}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "warped/services/base"
|
4
|
+
|
5
|
+
module Warped
|
6
|
+
module Queries
|
7
|
+
##
|
8
|
+
# Sorts a scope by a given key and direction
|
9
|
+
#
|
10
|
+
# This class provides a way to sort a scope by a given key and direction.
|
11
|
+
# It uses the +reorder+ method to sort the scope, so it will remove any existing order.
|
12
|
+
#
|
13
|
+
# @example Sort a scope by a key and direction
|
14
|
+
# Warped::Queries::Sort.call(User.all, sort_key: "name", sort_direction: "asc")
|
15
|
+
# # => #<ActiveRecord::Relation [...]>
|
16
|
+
#
|
17
|
+
# @example Sort a scope by a key with format +table.column+ and direction
|
18
|
+
# Warped::Queries::Sort.call(User.join(:accounts), sort_key: "accounts.updated_at", sort_direction: "asc")
|
19
|
+
# # => #<ActiveRecord::Relation [...]>
|
20
|
+
class Sort
|
21
|
+
SORT_DIRECTIONS = %w[asc desc].freeze
|
22
|
+
NULLS_SORT_DIRECTION = %w[asc_nulls_first asc_nulls_last desc_nulls_first desc_nulls_last].freeze
|
23
|
+
|
24
|
+
# @param scope [ActiveRecord::Relation] the scope to sort
|
25
|
+
# @param sort_key [String, Symbol] the key to sort by
|
26
|
+
# @param sort_direction [String, Symbol] the direction to sort by
|
27
|
+
# @return [ActiveRecord::Relation] the sorted scope
|
28
|
+
def self.call(scope, sort_key:, sort_direction: :desc)
|
29
|
+
new(scope, sort_key:, sort_direction:).call
|
30
|
+
end
|
31
|
+
|
32
|
+
# @param scope [ActiveRecord::Relation] the scope to sort
|
33
|
+
# @param sort_key [String, Symbol] the key to sort by
|
34
|
+
# @param sort_direction [String, Symbol] the direction to sort by
|
35
|
+
# @return [ActiveRecord::Relation] the sorted scope
|
36
|
+
def initialize(scope, sort_key:, sort_direction: :desc)
|
37
|
+
super()
|
38
|
+
@scope = scope
|
39
|
+
@sort_key = sort_key.to_s
|
40
|
+
@sort_direction = sort_direction.to_s.downcase
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return [ActiveRecord::Relation]
|
44
|
+
def call
|
45
|
+
validate_sort_direction!(sort_direction)
|
46
|
+
|
47
|
+
order = if NULLS_SORT_DIRECTION.include?(sort_direction)
|
48
|
+
arel_order
|
49
|
+
else
|
50
|
+
{ sort_key => sort_direction }
|
51
|
+
end
|
52
|
+
|
53
|
+
scope.reorder(order)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
attr_reader :scope, :sort_key, :sort_direction
|
59
|
+
|
60
|
+
def validate_sort_direction!(sort_direction)
|
61
|
+
return if SORT_DIRECTIONS.include?(sort_direction) || NULLS_SORT_DIRECTION.include?(sort_direction)
|
62
|
+
|
63
|
+
raise ArgumentError, "Invalid sort direction: #{sort_direction}, must be one of #{SORT_DIRECTIONS}"
|
64
|
+
end
|
65
|
+
|
66
|
+
def arel_order
|
67
|
+
arel_table.send(order_nulls_direction.first).send("nulls_#{order_nulls_direction.last}")
|
68
|
+
end
|
69
|
+
|
70
|
+
def arel_table
|
71
|
+
sort_key_arr = sort_key.split(".")
|
72
|
+
|
73
|
+
if sort_key_arr.size == 1
|
74
|
+
# sort_key has format 'column'
|
75
|
+
scope.klass.arel_table[sort_key]
|
76
|
+
else
|
77
|
+
# sort_key has format 'table.column'
|
78
|
+
Arel::Table.new(sort_key_arr.first)[sort_key_arr.last]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def order_nulls_direction
|
83
|
+
@order_nulls_direction ||= begin
|
84
|
+
order_nulls_dir = sort_direction.split("_")
|
85
|
+
[order_nulls_dir.first, order_nulls_dir.last]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "warped/jobs/base"
|
4
|
+
|
5
|
+
module Warped
|
6
|
+
module Services
|
7
|
+
# Base class for all services
|
8
|
+
#
|
9
|
+
# This class provides a simple interface for creating services.
|
10
|
+
# It also provides a way to call services asynchronously using +ActiveJob+.
|
11
|
+
#
|
12
|
+
# @example Create a service
|
13
|
+
# class PrintService < Warped::Services::Base
|
14
|
+
# def call(message)
|
15
|
+
# puts message
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# SomeService.call('Hello World') # => "Hello World"
|
20
|
+
# SomeService.new('Hello World').call # => "Hello World"
|
21
|
+
#
|
22
|
+
# @example Call a service asynchronously
|
23
|
+
# class SlowService < Warped::Services::Base
|
24
|
+
# enable_job!
|
25
|
+
#
|
26
|
+
# def call(message)
|
27
|
+
# sleep 5
|
28
|
+
# puts message
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# SlowService.call_later('Hello World') # => "Hello World" after 5 seconds
|
33
|
+
# SlowService::Job.perform_later('Hello World') # => "Hello World" after 5 seconds
|
34
|
+
class Base
|
35
|
+
def self.call(...)
|
36
|
+
new(...).call
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.call_later(...)
|
40
|
+
unless @job_enabled
|
41
|
+
message = "#{self.class.name}::Job is not implemented, make sure to call enable_job! in the service"
|
42
|
+
raise NotImplementedError, message
|
43
|
+
end
|
44
|
+
|
45
|
+
self::Async.perform_later(...)
|
46
|
+
end
|
47
|
+
|
48
|
+
def call
|
49
|
+
raise NotImplementedError, "#{self.class.name}#call not implemented"
|
50
|
+
end
|
51
|
+
|
52
|
+
# This method is used to create a Job class that inherits from +Warped::Jobs::Base+
|
53
|
+
# and calls the service asynchronously.
|
54
|
+
# @example Enable async for a service
|
55
|
+
# class SomeService < Warped::Services::Base
|
56
|
+
# enable_job!
|
57
|
+
#
|
58
|
+
# def call(...)
|
59
|
+
# # service logic
|
60
|
+
# end
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# # SomeService.call_later(...)
|
64
|
+
# # SomeService::Job.perform_later(...)
|
65
|
+
def self.enable_job!
|
66
|
+
@job_enabled = true
|
67
|
+
|
68
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
69
|
+
# class SomeService
|
70
|
+
# class Job < Warped::Jobs::Base
|
71
|
+
#
|
72
|
+
# def perform(...)
|
73
|
+
# SomeService.call(...)
|
74
|
+
# end
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# def self.call_later(...)
|
78
|
+
# Job.perform_later(...)
|
79
|
+
# end
|
80
|
+
# end
|
81
|
+
class Job < Warped::Jobs::Base
|
82
|
+
def perform(...)
|
83
|
+
#{name}.call(...)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.call_later(...)
|
88
|
+
Job.perform_later(...)
|
89
|
+
end
|
90
|
+
RUBY
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
data/lib/warped.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/configurable"
|
4
|
+
|
5
|
+
##
|
6
|
+
# The main module for the Warped gem.
|
7
|
+
#
|
8
|
+
# This module is used to provide configuration options for the gem.
|
9
|
+
#
|
10
|
+
# @example Configurations
|
11
|
+
# # config/initializers/warped.rb
|
12
|
+
#
|
13
|
+
# Warped.configure do |config|
|
14
|
+
# config.base_job_parent_class = "ApplicationJob" # Default: "ActiveJob::Base"
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# @see https://api.rubyonrails.org/classes/ActiveSupport/Configurable.html
|
18
|
+
#
|
19
|
+
module Warped
|
20
|
+
include ActiveSupport::Configurable
|
21
|
+
|
22
|
+
config_accessor :base_job_parent_class, instance_accessor: false, default: "ActiveJob::Base"
|
23
|
+
end
|
24
|
+
|
25
|
+
# load all files in lib/warped except for the tasks
|
26
|
+
require "zeitwerk"
|
27
|
+
loader = Zeitwerk::Loader.for_gem
|
28
|
+
loader.ignore("#{__dir__}/generators")
|
29
|
+
loader.ignore("lib/warped/railtie.rb") unless defined?(Rails::Railtie)
|
30
|
+
loader.setup
|
31
|
+
loader.eager_load
|
data/sig/warped.rbs
ADDED
data/warped.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/warped/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "warped"
|
7
|
+
spec.version = Warped::VERSION
|
8
|
+
spec.authors = ["Juan Aparicio"]
|
9
|
+
spec.email = ["apariciojuan30@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = "Set of modules to boost your Ruby on Rails development."
|
12
|
+
spec.homepage = "https://github.com/gogrow-dev/warped"
|
13
|
+
spec.license = "MIT"
|
14
|
+
spec.required_ruby_version = ">= 3.1.0"
|
15
|
+
|
16
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
17
|
+
spec.metadata["source_code_uri"] = "https://github.com/gogrow-dev/warped"
|
18
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
19
|
+
|
20
|
+
# Specify which files should be added to the gem when it is released.
|
21
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
22
|
+
spec.files = Dir.chdir(__dir__) do
|
23
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
24
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
25
|
+
end
|
26
|
+
end
|
27
|
+
spec.bindir = "exe"
|
28
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
29
|
+
spec.require_paths = ["lib"]
|
30
|
+
|
31
|
+
spec.add_dependency "rails", ">= 6.0", "< 8.0"
|
32
|
+
spec.add_dependency "zeitwerk", ">= 2.4"
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: warped
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Juan Aparicio
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-02-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '6.0'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '8.0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '6.0'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '8.0'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: zeitwerk
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '2.4'
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '2.4'
|
47
|
+
description:
|
48
|
+
email:
|
49
|
+
- apariciojuan30@gmail.com
|
50
|
+
executables: []
|
51
|
+
extensions: []
|
52
|
+
extra_rdoc_files: []
|
53
|
+
files:
|
54
|
+
- ".rspec"
|
55
|
+
- ".rubocop.yml"
|
56
|
+
- CHANGELOG.md
|
57
|
+
- CODE_OF_CONDUCT.md
|
58
|
+
- Gemfile
|
59
|
+
- Gemfile.lock
|
60
|
+
- LICENSE.txt
|
61
|
+
- README.md
|
62
|
+
- Rakefile
|
63
|
+
- lib/generators/warped/install_generator.rb
|
64
|
+
- lib/generators/warped/templates/initializer.rb.tt
|
65
|
+
- lib/warped.rb
|
66
|
+
- lib/warped/controllers/filterable.rb
|
67
|
+
- lib/warped/controllers/pageable.rb
|
68
|
+
- lib/warped/controllers/searchable.rb
|
69
|
+
- lib/warped/controllers/sortable.rb
|
70
|
+
- lib/warped/controllers/tabulatable.rb
|
71
|
+
- lib/warped/emails/.keep
|
72
|
+
- lib/warped/jobs/base.rb
|
73
|
+
- lib/warped/queries/filter.rb
|
74
|
+
- lib/warped/queries/paginate.rb
|
75
|
+
- lib/warped/queries/search.rb
|
76
|
+
- lib/warped/queries/sort.rb
|
77
|
+
- lib/warped/railtie.rb
|
78
|
+
- lib/warped/services/base.rb
|
79
|
+
- lib/warped/version.rb
|
80
|
+
- sig/warped.rbs
|
81
|
+
- warped.gemspec
|
82
|
+
homepage: https://github.com/gogrow-dev/warped
|
83
|
+
licenses:
|
84
|
+
- MIT
|
85
|
+
metadata:
|
86
|
+
homepage_uri: https://github.com/gogrow-dev/warped
|
87
|
+
source_code_uri: https://github.com/gogrow-dev/warped
|
88
|
+
rubygems_mfa_required: 'true'
|
89
|
+
post_install_message:
|
90
|
+
rdoc_options: []
|
91
|
+
require_paths:
|
92
|
+
- lib
|
93
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: 3.1.0
|
98
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
requirements: []
|
104
|
+
rubygems_version: 3.4.10
|
105
|
+
signing_key:
|
106
|
+
specification_version: 4
|
107
|
+
summary: Set of modules to boost your Ruby on Rails development.
|
108
|
+
test_files: []
|