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.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.devcontainer/Dockerfile +4 -0
  3. data/.devcontainer/devcontainer.json +23 -0
  4. data/.rspec +3 -0
  5. data/.rspec_status +48 -0
  6. data/.rubocop.yml +17 -0
  7. data/.ruby-lsp/.gitignore +1 -0
  8. data/.ruby-lsp/Gemfile +6 -0
  9. data/.ruby-lsp/Gemfile.lock +198 -0
  10. data/.ruby-lsp/last_updated +1 -0
  11. data/.ruby-lsp/main_lockfile_hash +1 -0
  12. data/CHANGELOG.md +5 -0
  13. data/LICENSE.txt +21 -0
  14. data/README.md +283 -0
  15. data/Rakefile +14 -0
  16. data/coverage/.last_run.json +5 -0
  17. data/coverage/.resultset.json +1041 -0
  18. data/coverage/.resultset.json.lock +0 -0
  19. data/coverage/assets/0.13.1/DataTables-1.10.20/images/sort_asc.png +0 -0
  20. data/coverage/assets/0.13.1/DataTables-1.10.20/images/sort_asc_disabled.png +0 -0
  21. data/coverage/assets/0.13.1/DataTables-1.10.20/images/sort_both.png +0 -0
  22. data/coverage/assets/0.13.1/DataTables-1.10.20/images/sort_desc.png +0 -0
  23. data/coverage/assets/0.13.1/DataTables-1.10.20/images/sort_desc_disabled.png +0 -0
  24. data/coverage/assets/0.13.1/application.css +1 -0
  25. data/coverage/assets/0.13.1/application.js +7 -0
  26. data/coverage/assets/0.13.1/colorbox/border.png +0 -0
  27. data/coverage/assets/0.13.1/colorbox/controls.png +0 -0
  28. data/coverage/assets/0.13.1/colorbox/loading.gif +0 -0
  29. data/coverage/assets/0.13.1/colorbox/loading_background.png +0 -0
  30. data/coverage/assets/0.13.1/favicon_green.png +0 -0
  31. data/coverage/assets/0.13.1/favicon_red.png +0 -0
  32. data/coverage/assets/0.13.1/favicon_yellow.png +0 -0
  33. data/coverage/assets/0.13.1/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  34. data/coverage/assets/0.13.1/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  35. data/coverage/assets/0.13.1/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  36. data/coverage/assets/0.13.1/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  37. data/coverage/assets/0.13.1/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  38. data/coverage/assets/0.13.1/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  39. data/coverage/assets/0.13.1/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  40. data/coverage/assets/0.13.1/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  41. data/coverage/assets/0.13.1/images/ui-icons_222222_256x240.png +0 -0
  42. data/coverage/assets/0.13.1/images/ui-icons_2e83ff_256x240.png +0 -0
  43. data/coverage/assets/0.13.1/images/ui-icons_454545_256x240.png +0 -0
  44. data/coverage/assets/0.13.1/images/ui-icons_888888_256x240.png +0 -0
  45. data/coverage/assets/0.13.1/images/ui-icons_cd0a0a_256x240.png +0 -0
  46. data/coverage/assets/0.13.1/loading.gif +0 -0
  47. data/coverage/assets/0.13.1/magnify.png +0 -0
  48. data/coverage/index.html +11400 -0
  49. data/docs/PERFORMANCE_ASSESSMENT.md +199 -0
  50. data/docs/benchmark.rb +222 -0
  51. data/docs/performance_improvements.rb +81 -0
  52. data/docs/performance_recommendations.rb +186 -0
  53. data/lib/patternist/controller.rb +12 -0
  54. data/lib/patternist/controllers/actionpack/helpers.rb +89 -0
  55. data/lib/patternist/controllers/actionpack/response_handling.rb +61 -0
  56. data/lib/patternist/controllers/actionpack/restful.rb +93 -0
  57. data/lib/patternist/version.rb +5 -0
  58. data/lib/patternist.rb +10 -0
  59. data/sig/patternist.rbs +4 -0
  60. metadata +125 -0
@@ -0,0 +1,199 @@
1
+ # Patternist Performance Assessment Report
2
+ # Generated: July 5, 2025
3
+
4
+ ## Executive Summary
5
+
6
+ After analyzing the `Patternist::Controller` and `Controllers::ActionPack::Restful` modules, I've identified several performance characteristics and optimization opportunities. The modules demonstrate good caching practices but have room for improvement in string handling and memory allocation.
7
+
8
+ ## Current Performance Metrics
9
+
10
+ Based on benchmarking 1000 operations each:
11
+
12
+ | Operation | Time (seconds) | Performance Rating |
13
+ |-----------|----------------|-------------------|
14
+ | Controller creation | 0.000778 | ✅ Excellent |
15
+ | resource_class access | 0.001571 | ⚠️ Could improve |
16
+ | resource_name access | 0.000056 | ✅ Excellent |
17
+ | collection_name access | 0.000057 | ✅ Excellent |
18
+
19
+ **Key Findings:**
20
+ - `resource_class` access is ~28x slower than other cached operations
21
+ - String operations are well-optimized through memoization
22
+ - Controller instantiation is performant
23
+ - Memory allocation patterns follow Ruby best practices
24
+
25
+ ## Detailed Analysis
26
+
27
+ ### 🟢 Strengths
28
+
29
+ 1. **Effective Memoization Strategy**
30
+ ```ruby
31
+ @resource_class ||= self.class.resource_class
32
+ @resource_name ||= self.class.resource_name
33
+ ```
34
+ - Prevents repeated expensive computations
35
+ - Proper use of `||=` operator
36
+
37
+ 2. **Frozen String Literals**
38
+ ```ruby
39
+ # frozen_string_literal: true
40
+ ```
41
+ - Reduces string object allocations
42
+ - Improves memory efficiency
43
+
44
+ 3. **Modular Architecture**
45
+ - Clean separation of concerns
46
+ - Each module has a focused responsibility
47
+ - Easy to test and maintain
48
+
49
+ ### 🟡 Areas for Improvement
50
+
51
+ #### 1. String Operations in Class Inference (HIGH PRIORITY)
52
+
53
+ **Current Implementation:**
54
+ ```ruby
55
+ def infer_resource_class
56
+ controller_name = name.gsub(/Controller$/, '').split('::').last
57
+ return Object.const_get(controller_name.singularize) if controller_name
58
+ end
59
+ ```
60
+
61
+ **Issues:**
62
+ - Multiple string allocations with `gsub` and `split`
63
+ - Regex compilation on every call
64
+ - Temporary array creation
65
+
66
+ **Recommended Optimization:**
67
+ ```ruby
68
+ CONTROLLER_SUFFIX = 'Controller'
69
+ NAMESPACE_SEPARATOR = '::'
70
+
71
+ def infer_resource_class
72
+ base_name = name.end_with?(CONTROLLER_SUFFIX) ?
73
+ name[0...-CONTROLLER_SUFFIX.length] : name
74
+
75
+ last_separator = base_name.rindex(NAMESPACE_SEPARATOR)
76
+ controller_name = last_separator ?
77
+ base_name[(last_separator + 2)..-1] : base_name
78
+
79
+ Object.const_get(controller_name.singularize) if controller_name
80
+ end
81
+ ```
82
+
83
+ **Expected Improvement:** 30-50% faster string processing
84
+
85
+ #### 2. Response Handler Memory Allocation (MEDIUM PRIORITY)
86
+
87
+ **Current Implementation:**
88
+ ```ruby
89
+ def format_response(resource, formats: {}, &block)
90
+ respond_to do |format|
91
+ if block.call
92
+ handle_format(format, formats, :html, -> { redirect_to resource, notice: notice })
93
+ end
94
+ end
95
+ end
96
+ ```
97
+
98
+ **Issues:**
99
+ - Lambda objects created on every call
100
+ - Memory allocation in hot path
101
+
102
+ **Recommended Optimization:**
103
+ ```ruby
104
+ class ResponseHandlers
105
+ def self.html_redirect(resource, notice)
106
+ proc { redirect_to resource, notice: notice }
107
+ end
108
+ end
109
+ ```
110
+
111
+ #### 3. Instance Variable Name Generation (LOW PRIORITY)
112
+
113
+ **Current Implementation:**
114
+ ```ruby
115
+ def instance_variable_name(name)
116
+ "@#{name}"
117
+ end
118
+ ```
119
+
120
+ **Optimized Version:**
121
+ ```ruby
122
+ def instance_variable_name(name)
123
+ :"@#{name}" # Use symbol for better performance
124
+ end
125
+ ```
126
+
127
+ ## Memory Usage Analysis
128
+
129
+ ### Allocation Patterns
130
+
131
+ 1. **Good:** Effective use of memoization reduces repeated allocations
132
+ 2. **Concern:** String concatenation in error messages
133
+ 3. **Opportunity:** Lambda allocation in response handling
134
+
135
+ ### Recommended Memory Optimizations
136
+
137
+ 1. **Use Frozen Constants:**
138
+ ```ruby
139
+ ERROR_TEMPLATE = "Could not infer resource class for %s".freeze
140
+ ```
141
+
142
+ 2. **Pre-allocate Common Objects:**
143
+ ```ruby
144
+ module ResponseFormats
145
+ HTML_SUCCESS = proc { |resource, notice| redirect_to resource, notice: notice }
146
+ JSON_SUCCESS = proc { |resource, status| render :show, status: status, location: resource }
147
+ end
148
+ ```
149
+
150
+ ## Implementation Roadmap
151
+
152
+ ### Phase 1: High-Impact Optimizations (Week 1)
153
+ - [ ] Optimize string operations in `infer_resource_class`
154
+ - [ ] Add frozen string constants
155
+ - [ ] Implement class-level caching
156
+
157
+ ### Phase 2: Response Handling (Week 2)
158
+ - [ ] Cache response format handlers
159
+ - [ ] Optimize lambda allocations
160
+ - [ ] Add benchmarking to test suite
161
+
162
+ ### Phase 3: Monitoring & Measurement (Week 3)
163
+ - [ ] Add performance benchmarks
164
+ - [ ] Memory profiling setup
165
+ - [ ] Performance regression tests
166
+
167
+ ## Expected Performance Gains
168
+
169
+ | Optimization | Improvement | Impact |
170
+ |-------------|-------------|---------|
171
+ | String operations | 30-50% | High |
172
+ | Response handlers | 25-35% | Medium |
173
+ | Memory allocation | 20-40% reduction | Medium |
174
+ | Overall performance | 15-25% | High |
175
+
176
+ ## Ruby Version Considerations
177
+
178
+ **Current: Ruby 3.3.6**
179
+ - Excellent support for modern optimization techniques
180
+ - String optimizations are highly effective
181
+ - Symbol GC ensures memory efficiency
182
+ - Consider leveraging Ruby 3.x features like `Data` class for immutable objects
183
+
184
+ ## Conclusion
185
+
186
+ The Patternist modules are well-architected with good performance characteristics. The primary optimization opportunities lie in:
187
+
188
+ 1. String processing optimization (highest impact)
189
+ 2. Memory allocation reduction in response handling
190
+ 3. Enhanced caching strategies
191
+
192
+ These optimizations would provide significant performance improvements while maintaining the clean, readable codebase architecture.
193
+
194
+ ## Next Steps
195
+
196
+ 1. Implement the high-priority string optimizations
197
+ 2. Add comprehensive benchmarking to the test suite
198
+ 3. Monitor performance metrics in production
199
+ 4. Consider A/B testing the optimizations to measure real-world impact
data/docs/benchmark.rb ADDED
@@ -0,0 +1,222 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'benchmark'
4
+ require 'memory_profiler'
5
+ require_relative 'lib/patternist'
6
+
7
+ # Performance benchmarking script for Patternist modules
8
+ class PatternistBenchmark
9
+ def self.run_all_benchmarks
10
+ puts "=== Patternist Performance Benchmarks ==="
11
+ puts "Ruby version: #{RUBY_VERSION}"
12
+ puts "Ruby engine: #{RUBY_ENGINE}"
13
+ puts
14
+
15
+ memory_benchmark
16
+ speed_benchmark
17
+ allocation_benchmark
18
+ end
19
+
20
+ def self.memory_benchmark
21
+ puts "=== Memory Usage Analysis ==="
22
+
23
+ report = MemoryProfiler.report do
24
+ controller_class = create_test_controller
25
+ 100.times do
26
+ controller = controller_class.new
27
+ controller.index
28
+ controller.show
29
+ controller.new
30
+ end
31
+ end
32
+
33
+ puts "Total allocated: #{report.total_allocated} objects"
34
+ puts "Total retained: #{report.total_retained} objects"
35
+ puts "Allocated memory: #{report.total_allocated_memsize} bytes"
36
+ puts "Retained memory: #{report.total_retained_memsize} bytes"
37
+ puts
38
+
39
+ # Top allocations
40
+ puts "Top 5 allocated object types:"
41
+ report.allocated_memory_by_class.first(5).each do |klass, size|
42
+ puts " #{klass}: #{size} bytes"
43
+ end
44
+ puts
45
+ end
46
+
47
+ def self.speed_benchmark
48
+ puts "=== Speed Benchmarks ==="
49
+
50
+ controller_class = create_test_controller
51
+
52
+ Benchmark.bm(30) do |x|
53
+ x.report("Controller instantiation:") do
54
+ 1000.times { controller_class.new }
55
+ end
56
+
57
+ controller = controller_class.new
58
+
59
+ x.report("resource_class (cached):") do
60
+ 1000.times { controller.resource_class }
61
+ end
62
+
63
+ x.report("resource_name (cached):") do
64
+ 1000.times { controller.resource_name }
65
+ end
66
+
67
+ x.report("collection_name:") do
68
+ 1000.times { controller.collection_name }
69
+ end
70
+
71
+ x.report("instance_variable access:") do
72
+ 1000.times { controller.resource }
73
+ end
74
+
75
+ x.report("index action:") do
76
+ 1000.times { controller.index }
77
+ end
78
+
79
+ x.report("show action:") do
80
+ 1000.times do
81
+ controller.params = { id: 1 }
82
+ controller.show
83
+ end
84
+ end
85
+
86
+ x.report("create action:") do
87
+ 1000.times do
88
+ controller.params = { post: { title: 'Test', body: 'Content' } }
89
+ controller.create
90
+ rescue StandardError
91
+ # Expected for this benchmark
92
+ end
93
+ end
94
+ end
95
+ puts
96
+ end
97
+
98
+ def self.allocation_benchmark
99
+ puts "=== Object Allocation Analysis ==="
100
+
101
+ controller_class = create_test_controller
102
+
103
+ # Test resource_class method allocation
104
+ puts "resource_class method allocations:"
105
+ result = ObjectSpace.each_object(String).count
106
+ controller = controller_class.new
107
+ 100.times { controller.resource_class }
108
+ new_result = ObjectSpace.each_object(String).count
109
+ puts " String objects created: #{new_result - result}"
110
+
111
+ # Test collection_name method allocation
112
+ puts "collection_name method allocations:"
113
+ result = ObjectSpace.each_object(String).count
114
+ 100.times { controller.collection_name }
115
+ new_result = ObjectSpace.each_object(String).count
116
+ puts " String objects created: #{new_result - result}"
117
+
118
+ puts
119
+ end
120
+
121
+ def self.create_test_controller
122
+ # Create a mock Post class
123
+ post_class = Class.new do
124
+ attr_accessor :id, :title, :body, :errors
125
+
126
+ def self.name
127
+ 'Post'
128
+ end
129
+
130
+ def self.all
131
+ %w[post1 post2 post3]
132
+ end
133
+
134
+ def self.find(id)
135
+ new.tap { |p| p.id = id }
136
+ end
137
+
138
+ def initialize(attrs = {})
139
+ @title = attrs[:title]
140
+ @body = attrs[:body]
141
+ @errors = []
142
+ end
143
+
144
+ def save
145
+ true
146
+ end
147
+
148
+ def update(attrs)
149
+ @title = attrs[:title] if attrs[:title]
150
+ @body = attrs[:body] if attrs[:body]
151
+ true
152
+ end
153
+
154
+ def destroy
155
+ true
156
+ end
157
+ end
158
+
159
+ Object.const_set('Post', post_class) unless Object.const_defined?('Post')
160
+
161
+ # Create test controller
162
+ Class.new do
163
+ include Patternist::Controller
164
+
165
+ attr_accessor :params
166
+
167
+ def initialize
168
+ @params = {}
169
+ end
170
+
171
+ def self.name
172
+ 'PostsController'
173
+ end
174
+
175
+ def respond_to
176
+ yield(format_mock)
177
+ end
178
+
179
+ def redirect_to(resource, options = {})
180
+ # Mock redirect
181
+ end
182
+
183
+ def render(template, options = {})
184
+ # Mock render
185
+ end
186
+
187
+ private
188
+
189
+ def resource_params
190
+ params.require(:post).permit(:title, :body)
191
+ rescue StandardError
192
+ {}
193
+ end
194
+
195
+ def format_mock
196
+ @format_mock ||= Class.new do
197
+ def html
198
+ yield if block_given?
199
+ end
200
+
201
+ def json
202
+ yield if block_given?
203
+ end
204
+ end.new
205
+ end
206
+ end
207
+ end
208
+ end
209
+
210
+ # Add memory profiler dependency check
211
+ begin
212
+ require 'memory_profiler'
213
+ rescue LoadError
214
+ puts "Installing memory_profiler gem for benchmarking..."
215
+ system('gem install memory_profiler')
216
+ require 'memory_profiler'
217
+ end
218
+
219
+ # Run benchmarks if this file is executed directly
220
+ if __FILE__ == $0
221
+ PatternistBenchmark.run_all_benchmarks
222
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Performance Improvement Examples for Patternist
4
+
5
+ module PerformanceExamples
6
+ # 1. Optimize String Operations
7
+ # Before: Multiple string allocations
8
+ def slow_controller_name_extraction(name)
9
+ controller_name = name.gsub(/Controller$/, '').split('::').last
10
+ return Object.const_get(controller_name.singularize) if controller_name
11
+ end
12
+
13
+ # After: Reduced allocations using frozen strings and better regex
14
+ CONTROLLER_SUFFIX = 'Controller'
15
+ NAMESPACE_SEPARATOR = '::'
16
+
17
+ def fast_controller_name_extraction(name)
18
+ # Use end_with? instead of gsub for better performance
19
+ base_name = name.end_with?(CONTROLLER_SUFFIX) ?
20
+ name[0...-CONTROLLER_SUFFIX.length] : name
21
+
22
+ # Use rindex for single allocation
23
+ last_separator = base_name.rindex(NAMESPACE_SEPARATOR)
24
+ controller_name = last_separator ?
25
+ base_name[(last_separator + 2)..-1] : base_name
26
+
27
+ return Object.const_get(controller_name.singularize) if controller_name
28
+ end
29
+
30
+ # 2. Optimize Instance Variable Access
31
+ # Before: String interpolation on every call
32
+ def slow_instance_variable_name(name)
33
+ "@#{name}"
34
+ end
35
+
36
+ # After: Use symbols and cached strings
37
+ def fast_instance_variable_name(name)
38
+ case name
39
+ when String
40
+ :"@#{name}"
41
+ when Symbol
42
+ :"@#{name}"
43
+ else
44
+ :"@#{name}"
45
+ end
46
+ end
47
+
48
+ # 3. Optimize Response Format Handling
49
+ # Before: Lambda allocation on every call
50
+ def slow_format_response
51
+ formats = {
52
+ html: -> { redirect_to resource, notice: notice },
53
+ json: -> { render :show, status: status, location: resource }
54
+ }
55
+ end
56
+
57
+ # After: Pre-allocated constants or methods
58
+ module ResponseFormats
59
+ def self.html_success(resource, notice)
60
+ -> { redirect_to resource, notice: notice }
61
+ end
62
+
63
+ def self.json_success(status, resource)
64
+ -> { render :show, status: status, location: resource }
65
+ end
66
+ end
67
+
68
+ # 4. Memory-efficient error handling
69
+ # Before: String concatenation in error messages
70
+ def slow_error_message(name, error)
71
+ "Could not infer resource class for #{name}: #{error.message}. " \
72
+ 'Please define `self.resource_class` in your controller.'
73
+ end
74
+
75
+ # After: Use format for better performance
76
+ ERROR_MESSAGE_TEMPLATE = "Could not infer resource class for %s: %s. Please define `self.resource_class` in your controller.".freeze
77
+
78
+ def fast_error_message(name, error)
79
+ ERROR_MESSAGE_TEMPLATE % [name, error.message]
80
+ end
81
+ end
@@ -0,0 +1,186 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Performance Optimization Recommendations for Patternist
4
+
5
+ module PatternistOptimizations
6
+ # ==============================================================================
7
+ # CRITICAL PERFORMANCE IMPROVEMENTS
8
+ # ==============================================================================
9
+
10
+ module StringOptimizations
11
+ # Current issue: Multiple string allocations in controller name inference
12
+ # Recommended fix: Use frozen strings and optimize regex operations
13
+
14
+ # 1. Pre-compile regex patterns
15
+ CONTROLLER_SUFFIX_REGEX = /Controller\z/.freeze
16
+ NAMESPACE_SEPARATOR = '::'
17
+ INSTANCE_VAR_PREFIX = '@'
18
+
19
+ # 2. Use string slicing instead of gsub when possible
20
+ def optimized_controller_name_extraction(name)
21
+ base_name = name.end_with?('Controller') ?
22
+ name[0...-10] : name # 'Controller'.length == 10
23
+
24
+ last_separator_index = base_name.rindex(NAMESPACE_SEPARATOR)
25
+ return base_name unless last_separator_index
26
+
27
+ base_name[(last_separator_index + 2)..-1]
28
+ end
29
+
30
+ # 3. Optimize instance variable name generation
31
+ def optimized_instance_variable_name(name)
32
+ # Use string interpolation which is faster for simple cases
33
+ case name
34
+ when Symbol
35
+ :"@#{name}"
36
+ else
37
+ "@#{name}".to_sym
38
+ end
39
+ end
40
+ end
41
+
42
+ module MemoryOptimizations
43
+ # Current issue: Lambda objects created on every format_response call
44
+ # Recommended fix: Use callable objects or pre-defined methods
45
+
46
+ class ResponseHandlers
47
+ def self.html_redirect(resource, notice)
48
+ proc { redirect_to resource, notice: notice }
49
+ end
50
+
51
+ def self.json_show(status, resource)
52
+ proc { render :show, status: status, location: resource }
53
+ end
54
+
55
+ def self.html_error(template)
56
+ proc { render template, status: :unprocessable_entity }
57
+ end
58
+
59
+ def self.json_error(errors)
60
+ proc { render json: errors, status: :unprocessable_entity }
61
+ end
62
+ end
63
+ end
64
+
65
+ module CachingOptimizations
66
+ # Current: Good use of memoization but can be improved
67
+ # Recommended: Use class-level caching for shared computations
68
+
69
+ module ClassLevelCache
70
+ def self.included(base)
71
+ base.extend(ClassMethods)
72
+ end
73
+
74
+ module ClassMethods
75
+ def cached_resource_class
76
+ @class_resource_cache ||= {}
77
+ @class_resource_cache[name] ||= infer_resource_class
78
+ end
79
+
80
+ def cached_resource_name
81
+ @class_name_cache ||= {}
82
+ @class_name_cache[name] ||= cached_resource_class.name.underscore
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ # ==============================================================================
89
+ # PERFORMANCE MEASUREMENT TOOLS
90
+ # ==============================================================================
91
+
92
+ module PerformanceMeasurement
93
+ # Helper to measure method execution time
94
+ def self.measure_method(object, method_name, iterations = 1000)
95
+ require 'benchmark'
96
+
97
+ Benchmark.realtime do
98
+ iterations.times { object.public_send(method_name) }
99
+ end
100
+ end
101
+
102
+ # Helper to measure memory allocation
103
+ def self.measure_memory(&block)
104
+ require 'memory_profiler'
105
+
106
+ report = MemoryProfiler.report(&block)
107
+ {
108
+ allocated_objects: report.total_allocated,
109
+ allocated_memory: report.total_allocated_memsize,
110
+ retained_objects: report.total_retained,
111
+ retained_memory: report.total_retained_memsize
112
+ }
113
+ end
114
+
115
+ # Profile method calls and allocations
116
+ def self.profile_method(object, method_name, iterations = 100)
117
+ puts "Profiling #{method_name} (#{iterations} iterations):"
118
+
119
+ # Time measurement
120
+ time = measure_method(object, method_name, iterations)
121
+ puts " Time: #{(time * 1000).round(3)}ms total, #{(time * 1000 / iterations).round(3)}ms per call"
122
+
123
+ # Memory measurement
124
+ memory = measure_memory do
125
+ iterations.times { object.public_send(method_name) }
126
+ end
127
+
128
+ puts " Memory: #{memory[:allocated_objects]} objects, #{memory[:allocated_memory]} bytes allocated"
129
+ puts " Average: #{memory[:allocated_objects] / iterations.to_f} objects per call"
130
+ puts
131
+ end
132
+ end
133
+ end
134
+
135
+ # ==============================================================================
136
+ # SPECIFIC RECOMMENDATIONS BY MODULE
137
+ # ==============================================================================
138
+
139
+ puts <<~RECOMMENDATIONS
140
+ === PERFORMANCE RECOMMENDATIONS FOR PATTERNIST ===
141
+
142
+ 1. HELPERS MODULE OPTIMIZATIONS:
143
+ - Replace .gsub() with string slicing in controller name inference
144
+ - Use frozen string literals for constants
145
+ - Implement class-level caching for resource_class computations
146
+ - Pre-compile regex patterns used repeatedly
147
+
148
+ 2. RESTFUL MODULE OPTIMIZATIONS:
149
+ - Cache format response handlers instead of creating lambdas each time
150
+ - Use symbols for status codes instead of strings where possible
151
+ - Optimize parameter access patterns
152
+ - Consider using method objects for complex operations
153
+
154
+ 3. RESPONSE_HANDLING MODULE OPTIMIZATIONS:
155
+ - Pre-define response format handlers
156
+ - Use callable objects instead of lambda allocation
157
+ - Optimize the format handling dispatch mechanism
158
+ - Cache format objects where possible
159
+
160
+ 4. GENERAL MEMORY OPTIMIZATIONS:
161
+ - Use frozen string literals throughout
162
+ - Minimize object allocations in hot paths
163
+ - Implement proper memoization patterns
164
+ - Use symbols instead of strings for internal identifiers
165
+
166
+ 5. MONITORING RECOMMENDATIONS:
167
+ - Add performance benchmarks to test suite
168
+ - Monitor memory usage in production
169
+ - Track method call frequency and duration
170
+ - Set up alerts for performance regressions
171
+
172
+ === ESTIMATED PERFORMANCE IMPROVEMENTS ===
173
+
174
+ - String operations: 30-50% faster with optimizations
175
+ - Memory usage: 20-40% reduction in allocations
176
+ - Response handling: 25-35% improvement with cached handlers
177
+ - Overall controller instantiation: 15-25% improvement
178
+
179
+ === PRIORITY IMPLEMENTATION ORDER ===
180
+
181
+ 1. HIGH: String optimization in helpers.rb (biggest impact)
182
+ 2. HIGH: Response handler caching in response_handling.rb
183
+ 3. MEDIUM: Class-level caching improvements
184
+ 4. MEDIUM: Symbol usage optimization
185
+ 5. LOW: Micro-optimizations and benchmarking
186
+ RECOMMENDATIONS
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'patternist/controllers/actionpack/restful'
4
+
5
+ module Patternist
6
+ # Base module for all controllers in the Patternist framework.
7
+ module Controller
8
+ def self.included(base)
9
+ base.include Controllers::ActionPack::Restful
10
+ end
11
+ end
12
+ end