patternist 0.1.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/.devcontainer/Dockerfile +4 -0
- data/.devcontainer/devcontainer.json +23 -0
- data/.rspec +3 -0
- data/.rspec_status +48 -0
- data/.rubocop.yml +17 -0
- data/.ruby-lsp/.gitignore +1 -0
- data/.ruby-lsp/Gemfile +6 -0
- data/.ruby-lsp/Gemfile.lock +198 -0
- data/.ruby-lsp/last_updated +1 -0
- data/.ruby-lsp/main_lockfile_hash +1 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +283 -0
- data/Rakefile +14 -0
- data/coverage/.last_run.json +5 -0
- data/coverage/.resultset.json +1041 -0
- data/coverage/.resultset.json.lock +0 -0
- data/coverage/assets/0.13.1/DataTables-1.10.20/images/sort_asc.png +0 -0
- data/coverage/assets/0.13.1/DataTables-1.10.20/images/sort_asc_disabled.png +0 -0
- data/coverage/assets/0.13.1/DataTables-1.10.20/images/sort_both.png +0 -0
- data/coverage/assets/0.13.1/DataTables-1.10.20/images/sort_desc.png +0 -0
- data/coverage/assets/0.13.1/DataTables-1.10.20/images/sort_desc_disabled.png +0 -0
- data/coverage/assets/0.13.1/application.css +1 -0
- data/coverage/assets/0.13.1/application.js +7 -0
- data/coverage/assets/0.13.1/colorbox/border.png +0 -0
- data/coverage/assets/0.13.1/colorbox/controls.png +0 -0
- data/coverage/assets/0.13.1/colorbox/loading.gif +0 -0
- data/coverage/assets/0.13.1/colorbox/loading_background.png +0 -0
- data/coverage/assets/0.13.1/favicon_green.png +0 -0
- data/coverage/assets/0.13.1/favicon_red.png +0 -0
- data/coverage/assets/0.13.1/favicon_yellow.png +0 -0
- data/coverage/assets/0.13.1/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/coverage/assets/0.13.1/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/coverage/assets/0.13.1/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/coverage/assets/0.13.1/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/coverage/assets/0.13.1/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/coverage/assets/0.13.1/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/coverage/assets/0.13.1/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/coverage/assets/0.13.1/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/coverage/assets/0.13.1/images/ui-icons_222222_256x240.png +0 -0
- data/coverage/assets/0.13.1/images/ui-icons_2e83ff_256x240.png +0 -0
- data/coverage/assets/0.13.1/images/ui-icons_454545_256x240.png +0 -0
- data/coverage/assets/0.13.1/images/ui-icons_888888_256x240.png +0 -0
- data/coverage/assets/0.13.1/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/coverage/assets/0.13.1/loading.gif +0 -0
- data/coverage/assets/0.13.1/magnify.png +0 -0
- data/coverage/index.html +11400 -0
- data/docs/PERFORMANCE_ASSESSMENT.md +199 -0
- data/docs/benchmark.rb +222 -0
- data/docs/performance_improvements.rb +81 -0
- data/docs/performance_recommendations.rb +186 -0
- data/lib/patternist/controller.rb +12 -0
- data/lib/patternist/controllers/actionpack/helpers.rb +89 -0
- data/lib/patternist/controllers/actionpack/response_handling.rb +61 -0
- data/lib/patternist/controllers/actionpack/restful.rb +93 -0
- data/lib/patternist/version.rb +5 -0
- data/lib/patternist.rb +10 -0
- data/sig/patternist.rbs +4 -0
- metadata +125 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support/core_ext/string/inflections'
|
|
4
|
+
|
|
5
|
+
module Patternist
|
|
6
|
+
module Controllers
|
|
7
|
+
module ActionPack
|
|
8
|
+
# Provides helper methods for controller resource handling and naming conventions.
|
|
9
|
+
# Automatically infers resource classes and names based on controller naming.
|
|
10
|
+
module Helpers
|
|
11
|
+
CONTROLLER_SUFFIX = 'Controller'
|
|
12
|
+
NAMESPACE_SEPARATOR = '::'
|
|
13
|
+
|
|
14
|
+
def self.included(base)
|
|
15
|
+
base.extend ClassMethods
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def collection = resource_class.all
|
|
19
|
+
def find_resource = resource_class.find(id_param)
|
|
20
|
+
def create_resource = resource.save
|
|
21
|
+
def update_resource = resource.update(resource_params)
|
|
22
|
+
def destroy_resource = resource.destroy
|
|
23
|
+
def resource_class = @resource_class ||= self.class.resource_class
|
|
24
|
+
def resource_name = @resource_name ||= self.class.resource_name
|
|
25
|
+
def resource_class_name = @resource_class_name ||= model_name_human || resource_class.name
|
|
26
|
+
def collection_name = @collection_name ||= resource_name.pluralize
|
|
27
|
+
def resource = instance_variable_get(instance_variable_name(resource_name))
|
|
28
|
+
def id_param = params.fetch(params_id_key, nil)
|
|
29
|
+
def params_id_key = :id
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def model_name_human
|
|
34
|
+
resource_class.respond_to?(:model_name) && resource_class.model_name.human
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def collection_instance=(value)
|
|
38
|
+
instance_variable_set(instance_variable_name(collection_name), value)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def resource_instance=(value)
|
|
42
|
+
instance_variable_set(instance_variable_name(resource_name), value)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def instance_variable_name(name)
|
|
46
|
+
:"@#{name}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Class methods automatically added to the including class
|
|
50
|
+
module ClassMethods
|
|
51
|
+
# Infers the resource class from the controller name
|
|
52
|
+
def resource_class
|
|
53
|
+
@resource_class ||= infer_resource_class
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Returns the underscored name of the resource class
|
|
57
|
+
def resource_name
|
|
58
|
+
@resource_name ||= resource_class.name.underscore
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
# Infers the resource class based on the controller name
|
|
64
|
+
def infer_resource_class
|
|
65
|
+
base_name = if name.end_with?(CONTROLLER_SUFFIX)
|
|
66
|
+
name[0...-CONTROLLER_SUFFIX.length]
|
|
67
|
+
else
|
|
68
|
+
name
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
last_separator = base_name.rindex(NAMESPACE_SEPARATOR)
|
|
72
|
+
controller_name = if last_separator
|
|
73
|
+
base_name[(last_separator + 2)..]
|
|
74
|
+
else
|
|
75
|
+
base_name
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
Object.const_get(controller_name.singularize) if controller_name
|
|
79
|
+
rescue NameError => e
|
|
80
|
+
raise NameError, "Could not infer resource class for #{name}: #{e.message}. " \
|
|
81
|
+
'Please define `self.resource_class` in your controller.'
|
|
82
|
+
rescue StandardError => e
|
|
83
|
+
raise NameError, "An error occurred while inferring resource class for #{name}: #{e.message}."
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Patternist
|
|
4
|
+
module Controllers
|
|
5
|
+
module ActionPack
|
|
6
|
+
# Handles HTTP and JSON response formatting for controllers.
|
|
7
|
+
# Provides consistent response patterns across controllers with customizable handlers.
|
|
8
|
+
module ResponseHandling
|
|
9
|
+
HTML_FORMAT = :html
|
|
10
|
+
JSON_FORMAT = :json
|
|
11
|
+
|
|
12
|
+
def format_response(resource, notice:, status:, on_error_render:, formats: {}, &block)
|
|
13
|
+
respond_to do |format|
|
|
14
|
+
if block.call
|
|
15
|
+
handle_success(format, resource, notice, status, formats)
|
|
16
|
+
else
|
|
17
|
+
handle_error(format, resource, on_error_render, formats)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
# Handles successful responses for different formats
|
|
25
|
+
def handle_success(format, resource, notice, status, custom_formats)
|
|
26
|
+
# TODO: DEPRECATE custom_formats?
|
|
27
|
+
dispatch_response(format, HTML_FORMAT, html_success(resource, notice: notice), custom_formats)
|
|
28
|
+
dispatch_response(format, JSON_FORMAT, json_success(resource, status: status), custom_formats)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Handles error responses for different formats
|
|
32
|
+
def handle_error(format, resource, on_error_render, custom_formats)
|
|
33
|
+
dispatch_response(format, HTML_FORMAT, html_error(on_error_render), custom_formats, :on_error_html)
|
|
34
|
+
dispatch_response(format, JSON_FORMAT, json_error(resource), custom_formats, :on_error_json)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def html_success(location, notice:)
|
|
38
|
+
proc { redirect_to location, notice: notice }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def json_success(location, status:)
|
|
42
|
+
proc { render :show, status: status, location: location }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def html_error(on_error_render, status: :unprocessable_entity)
|
|
46
|
+
proc { render on_error_render, status: status }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def json_error(resource, status: :unprocessable_entity)
|
|
50
|
+
proc { render json: resource.errors, status: status }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def dispatch_response(format, format_method, default_proc, custom_procs, format_key = format_method)
|
|
54
|
+
format.public_send(format_method) do
|
|
55
|
+
(custom_procs[format_key] || default_proc).call
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'helpers'
|
|
4
|
+
require_relative 'response_handling'
|
|
5
|
+
|
|
6
|
+
module Patternist
|
|
7
|
+
module Controllers
|
|
8
|
+
module ActionPack
|
|
9
|
+
# Provides RESTful CRUD actions for controllers.
|
|
10
|
+
# Requires implementing `resource_params` for strong parameter handling.
|
|
11
|
+
module Restful
|
|
12
|
+
def self.included(base)
|
|
13
|
+
base.include Helpers
|
|
14
|
+
base.include ResponseHandling
|
|
15
|
+
base.include InstanceMethods
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Instance methods implementing RESTful actions
|
|
19
|
+
module InstanceMethods
|
|
20
|
+
# Lists all resources
|
|
21
|
+
def index = self.collection_instance = collection
|
|
22
|
+
|
|
23
|
+
# Shows a single resource
|
|
24
|
+
def show
|
|
25
|
+
self.resource_instance = find_resource
|
|
26
|
+
yield if block_given?
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Prepares a resource for editing
|
|
30
|
+
def edit
|
|
31
|
+
self.resource_instance = find_resource
|
|
32
|
+
yield if block_given?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Initializes a new resource
|
|
36
|
+
def new
|
|
37
|
+
self.resource_instance = resource_class.new
|
|
38
|
+
yield if block_given?
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Creates a new resource
|
|
42
|
+
def create
|
|
43
|
+
self.resource_instance = resource_class.new(resource_params)
|
|
44
|
+
|
|
45
|
+
format_response(resource,
|
|
46
|
+
notice: "#{resource_class_name} was successfully created.",
|
|
47
|
+
status: :created,
|
|
48
|
+
on_error_render: :new) do
|
|
49
|
+
create_resource
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Updates an existing resource
|
|
54
|
+
def update
|
|
55
|
+
self.resource_instance = find_resource
|
|
56
|
+
|
|
57
|
+
format_response(resource,
|
|
58
|
+
notice: "#{resource_class_name} was successfully updated.",
|
|
59
|
+
status: :ok,
|
|
60
|
+
on_error_render: :edit) do
|
|
61
|
+
update_resource
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Destroys an existing resource
|
|
66
|
+
def destroy
|
|
67
|
+
self.resource_instance = find_resource
|
|
68
|
+
|
|
69
|
+
notice = "#{resource_class_name} was successfully destroyed."
|
|
70
|
+
format_response(resource,
|
|
71
|
+
notice: notice,
|
|
72
|
+
status: :see_other,
|
|
73
|
+
on_error_render: :show,
|
|
74
|
+
formats: {
|
|
75
|
+
html: -> { redirect_to resource_class, notice: notice },
|
|
76
|
+
json: -> { head :no_content }
|
|
77
|
+
}) do
|
|
78
|
+
destroy_resource
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
protected
|
|
83
|
+
|
|
84
|
+
# Override this method to define allowed parameters
|
|
85
|
+
def resource_params
|
|
86
|
+
raise NotImplementedError,
|
|
87
|
+
'Controller must define `resource_params`. Example: `params.require(:post).permit(:title, :body)`'
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
data/lib/patternist.rb
ADDED
data/sig/patternist.rbs
ADDED
metadata
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: patternist
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Emerson Xavier
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2025-07-11 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: actionpack
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '4.0'
|
|
20
|
+
- - "<"
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: '9.0'
|
|
23
|
+
type: :runtime
|
|
24
|
+
prerelease: false
|
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
26
|
+
requirements:
|
|
27
|
+
- - ">="
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '4.0'
|
|
30
|
+
- - "<"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '9.0'
|
|
33
|
+
description: Reusable utilities for Ruby and Rails
|
|
34
|
+
email:
|
|
35
|
+
- msxavii@gmail.com
|
|
36
|
+
executables: []
|
|
37
|
+
extensions: []
|
|
38
|
+
extra_rdoc_files: []
|
|
39
|
+
files:
|
|
40
|
+
- ".devcontainer/Dockerfile"
|
|
41
|
+
- ".devcontainer/devcontainer.json"
|
|
42
|
+
- ".rspec"
|
|
43
|
+
- ".rspec_status"
|
|
44
|
+
- ".rubocop.yml"
|
|
45
|
+
- ".ruby-lsp/.gitignore"
|
|
46
|
+
- ".ruby-lsp/Gemfile"
|
|
47
|
+
- ".ruby-lsp/Gemfile.lock"
|
|
48
|
+
- ".ruby-lsp/last_updated"
|
|
49
|
+
- ".ruby-lsp/main_lockfile_hash"
|
|
50
|
+
- CHANGELOG.md
|
|
51
|
+
- LICENSE.txt
|
|
52
|
+
- README.md
|
|
53
|
+
- Rakefile
|
|
54
|
+
- coverage/.last_run.json
|
|
55
|
+
- coverage/.resultset.json
|
|
56
|
+
- coverage/.resultset.json.lock
|
|
57
|
+
- coverage/assets/0.13.1/DataTables-1.10.20/images/sort_asc.png
|
|
58
|
+
- coverage/assets/0.13.1/DataTables-1.10.20/images/sort_asc_disabled.png
|
|
59
|
+
- coverage/assets/0.13.1/DataTables-1.10.20/images/sort_both.png
|
|
60
|
+
- coverage/assets/0.13.1/DataTables-1.10.20/images/sort_desc.png
|
|
61
|
+
- coverage/assets/0.13.1/DataTables-1.10.20/images/sort_desc_disabled.png
|
|
62
|
+
- coverage/assets/0.13.1/application.css
|
|
63
|
+
- coverage/assets/0.13.1/application.js
|
|
64
|
+
- coverage/assets/0.13.1/colorbox/border.png
|
|
65
|
+
- coverage/assets/0.13.1/colorbox/controls.png
|
|
66
|
+
- coverage/assets/0.13.1/colorbox/loading.gif
|
|
67
|
+
- coverage/assets/0.13.1/colorbox/loading_background.png
|
|
68
|
+
- coverage/assets/0.13.1/favicon_green.png
|
|
69
|
+
- coverage/assets/0.13.1/favicon_red.png
|
|
70
|
+
- coverage/assets/0.13.1/favicon_yellow.png
|
|
71
|
+
- coverage/assets/0.13.1/images/ui-bg_flat_0_aaaaaa_40x100.png
|
|
72
|
+
- coverage/assets/0.13.1/images/ui-bg_flat_75_ffffff_40x100.png
|
|
73
|
+
- coverage/assets/0.13.1/images/ui-bg_glass_55_fbf9ee_1x400.png
|
|
74
|
+
- coverage/assets/0.13.1/images/ui-bg_glass_65_ffffff_1x400.png
|
|
75
|
+
- coverage/assets/0.13.1/images/ui-bg_glass_75_dadada_1x400.png
|
|
76
|
+
- coverage/assets/0.13.1/images/ui-bg_glass_75_e6e6e6_1x400.png
|
|
77
|
+
- coverage/assets/0.13.1/images/ui-bg_glass_95_fef1ec_1x400.png
|
|
78
|
+
- coverage/assets/0.13.1/images/ui-bg_highlight-soft_75_cccccc_1x100.png
|
|
79
|
+
- coverage/assets/0.13.1/images/ui-icons_222222_256x240.png
|
|
80
|
+
- coverage/assets/0.13.1/images/ui-icons_2e83ff_256x240.png
|
|
81
|
+
- coverage/assets/0.13.1/images/ui-icons_454545_256x240.png
|
|
82
|
+
- coverage/assets/0.13.1/images/ui-icons_888888_256x240.png
|
|
83
|
+
- coverage/assets/0.13.1/images/ui-icons_cd0a0a_256x240.png
|
|
84
|
+
- coverage/assets/0.13.1/loading.gif
|
|
85
|
+
- coverage/assets/0.13.1/magnify.png
|
|
86
|
+
- coverage/index.html
|
|
87
|
+
- docs/PERFORMANCE_ASSESSMENT.md
|
|
88
|
+
- docs/benchmark.rb
|
|
89
|
+
- docs/performance_improvements.rb
|
|
90
|
+
- docs/performance_recommendations.rb
|
|
91
|
+
- lib/patternist.rb
|
|
92
|
+
- lib/patternist/controller.rb
|
|
93
|
+
- lib/patternist/controllers/actionpack/helpers.rb
|
|
94
|
+
- lib/patternist/controllers/actionpack/response_handling.rb
|
|
95
|
+
- lib/patternist/controllers/actionpack/restful.rb
|
|
96
|
+
- lib/patternist/version.rb
|
|
97
|
+
- sig/patternist.rbs
|
|
98
|
+
homepage: https://github.com/xavius-rb/patternist
|
|
99
|
+
licenses:
|
|
100
|
+
- MIT
|
|
101
|
+
metadata:
|
|
102
|
+
allowed_push_host: https://rubygems.org/
|
|
103
|
+
homepage_uri: https://github.com/xavius-rb/patternist
|
|
104
|
+
source_code_uri: https://github.com/xavius-rb/patternist
|
|
105
|
+
changelog_uri: https://github.com/xavius-rb/patternist/blob/main/CHANGELOG.md
|
|
106
|
+
post_install_message:
|
|
107
|
+
rdoc_options: []
|
|
108
|
+
require_paths:
|
|
109
|
+
- lib
|
|
110
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
111
|
+
requirements:
|
|
112
|
+
- - ">="
|
|
113
|
+
- !ruby/object:Gem::Version
|
|
114
|
+
version: 3.1.0
|
|
115
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
116
|
+
requirements:
|
|
117
|
+
- - ">="
|
|
118
|
+
- !ruby/object:Gem::Version
|
|
119
|
+
version: '0'
|
|
120
|
+
requirements: []
|
|
121
|
+
rubygems_version: 3.0.3.1
|
|
122
|
+
signing_key:
|
|
123
|
+
specification_version: 4
|
|
124
|
+
summary: Reusable utilities
|
|
125
|
+
test_files: []
|