rails_console_pro 0.1.1 → 0.1.3

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec_status +261 -240
  3. data/CHANGELOG.md +4 -0
  4. data/QUICK_START.md +8 -0
  5. data/README.md +16 -0
  6. data/docs/FORMATTING.md +5 -0
  7. data/docs/MODEL_STATISTICS.md +4 -0
  8. data/docs/OBJECT_DIFFING.md +6 -0
  9. data/docs/PROFILING.md +91 -0
  10. data/docs/QUEUE_INSIGHTS.md +82 -0
  11. data/docs/SCHEMA_INSPECTION.md +5 -0
  12. data/docs/SNIPPETS.md +71 -0
  13. data/lib/rails_console_pro/commands/base_command.rb +1 -1
  14. data/lib/rails_console_pro/commands/jobs_command.rb +212 -0
  15. data/lib/rails_console_pro/commands/profile_command.rb +84 -0
  16. data/lib/rails_console_pro/commands/snippets_command.rb +141 -0
  17. data/lib/rails_console_pro/commands.rb +15 -0
  18. data/lib/rails_console_pro/configuration.rb +39 -0
  19. data/lib/rails_console_pro/format_exporter.rb +8 -0
  20. data/lib/rails_console_pro/global_methods.rb +12 -0
  21. data/lib/rails_console_pro/initializer.rb +29 -4
  22. data/lib/rails_console_pro/model_validator.rb +1 -1
  23. data/lib/rails_console_pro/printers/profile_printer.rb +180 -0
  24. data/lib/rails_console_pro/printers/queue_insights_printer.rb +150 -0
  25. data/lib/rails_console_pro/printers/snippet_collection_printer.rb +68 -0
  26. data/lib/rails_console_pro/printers/snippet_printer.rb +64 -0
  27. data/lib/rails_console_pro/profile_result.rb +109 -0
  28. data/lib/rails_console_pro/pry_commands.rb +106 -0
  29. data/lib/rails_console_pro/queue_insights_result.rb +110 -0
  30. data/lib/rails_console_pro/serializers/profile_serializer.rb +73 -0
  31. data/lib/rails_console_pro/services/profile_collector.rb +245 -0
  32. data/lib/rails_console_pro/services/queue_action_service.rb +176 -0
  33. data/lib/rails_console_pro/services/queue_insight_fetcher.rb +600 -0
  34. data/lib/rails_console_pro/services/snippet_repository.rb +191 -0
  35. data/lib/rails_console_pro/snippets/collection_result.rb +44 -0
  36. data/lib/rails_console_pro/snippets/single_result.rb +30 -0
  37. data/lib/rails_console_pro/snippets/snippet.rb +112 -0
  38. data/lib/rails_console_pro/snippets.rb +12 -0
  39. data/lib/rails_console_pro/version.rb +1 -1
  40. data/rails_console_pro.gemspec +1 -1
  41. metadata +26 -8
@@ -0,0 +1,191 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+ require 'fileutils'
5
+ require 'securerandom'
6
+
7
+ module RailsConsolePro
8
+ module Services
9
+ # Persistence layer for console snippets
10
+ class SnippetRepository
11
+ include Enumerable
12
+
13
+ DEFAULT_LIMIT = 20
14
+
15
+ def initialize(store_path:)
16
+ @store_path = File.expand_path(store_path)
17
+ end
18
+
19
+ def each(&block)
20
+ all.each(&block)
21
+ end
22
+
23
+ def all(limit: nil)
24
+ snippets = load_snippets.values.sort_by(&:updated_at).reverse
25
+ limit ? snippets.first(limit) : snippets
26
+ end
27
+
28
+ def find(id)
29
+ load_snippets[normalize_id(id)]
30
+ end
31
+
32
+ def search(term: nil, tags: nil, limit: nil)
33
+ snippets = all
34
+ term_value = normalize_query(term)
35
+ tag_value = normalize_tags(tags)
36
+
37
+ filtered = snippets.select do |snippet|
38
+ snippet.matches?(term: term_value, tags: tag_value)
39
+ end
40
+
41
+ {
42
+ results: limit ? filtered.first(limit) : filtered,
43
+ total_count: filtered.size
44
+ }
45
+ end
46
+
47
+ def add(body:, id: nil, tags: nil, description: nil, favorite: false, metadata: nil)
48
+ snippet = Snippets::Snippet.new(
49
+ id: id || generate_id(description: description, body: body),
50
+ body: body,
51
+ tags: tags,
52
+ description: description,
53
+ created_at: Time.now,
54
+ updated_at: Time.now,
55
+ favorite: favorite,
56
+ metadata: metadata
57
+ )
58
+
59
+ persist(snippet)
60
+ snippet
61
+ end
62
+
63
+ def update(id, **attributes)
64
+ snippet = find(id)
65
+ return unless snippet
66
+
67
+ updated_snippet = snippet.with(**attributes.merge(updated_at: Time.now))
68
+ persist(updated_snippet)
69
+ updated_snippet
70
+ end
71
+
72
+ def delete(id)
73
+ normalized_id = normalize_id(id)
74
+ data = load_data
75
+ return false unless data.key?(normalized_id)
76
+
77
+ data.delete(normalized_id)
78
+ write_data(data)
79
+ true
80
+ end
81
+
82
+ def clear
83
+ write_data({})
84
+ end
85
+
86
+ private
87
+
88
+ attr_reader :store_path
89
+
90
+ def persist(snippet)
91
+ data = load_data
92
+ data[snippet.id] = serialize(snippet)
93
+ write_data(data)
94
+ snippet
95
+ end
96
+
97
+ def load_snippets
98
+ load_data.transform_values { |attrs| deserialize(attrs) }
99
+ end
100
+
101
+ def load_data
102
+ return {} unless File.exist?(store_path)
103
+
104
+ YAML.safe_load(File.read(store_path), permitted_classes: [Time], aliases: true) || {}
105
+ rescue Psych::SyntaxError
106
+ {}
107
+ end
108
+
109
+ def write_data(data)
110
+ FileUtils.mkdir_p(File.dirname(store_path))
111
+
112
+ File.open(store_path, File::RDWR | File::CREAT, 0o600) do |file|
113
+ file.flock(File::LOCK_EX)
114
+ file.rewind
115
+ file.truncate(0)
116
+ file.write(data.to_yaml)
117
+ file.flush
118
+ ensure
119
+ file.flock(File::LOCK_UN)
120
+ end
121
+
122
+ true
123
+ end
124
+
125
+ def serialize(snippet)
126
+ {
127
+ 'id' => snippet.id,
128
+ 'body' => snippet.body,
129
+ 'tags' => snippet.tags,
130
+ 'description' => snippet.description,
131
+ 'created_at' => snippet.created_at.utc.iso8601,
132
+ 'updated_at' => snippet.updated_at.utc.iso8601,
133
+ 'favorite' => snippet.favorite?,
134
+ 'metadata' => snippet.metadata
135
+ }
136
+ end
137
+
138
+ def deserialize(attrs)
139
+ Snippets::Snippet.new(
140
+ id: attrs['id'],
141
+ body: attrs['body'],
142
+ tags: attrs['tags'],
143
+ description: attrs['description'],
144
+ created_at: attrs['created_at'],
145
+ updated_at: attrs['updated_at'],
146
+ favorite: attrs['favorite'],
147
+ metadata: attrs['metadata']
148
+ )
149
+ end
150
+
151
+ def normalize_id(id)
152
+ id.to_s.strip.downcase.gsub(/\s+/, '-')
153
+ end
154
+
155
+ def normalize_query(term)
156
+ return if term.nil?
157
+ term.to_s.strip.downcase
158
+ end
159
+
160
+ def normalize_tags(tags)
161
+ return if tags.nil?
162
+ Array(tags).compact.map { |tag| tag.to_s.strip.downcase }.reject(&:empty?)
163
+ end
164
+
165
+ def generate_id(description:, body:)
166
+ base =
167
+ if description && !description.strip.empty?
168
+ description
169
+ else
170
+ body.to_s.lines.first.to_s.strip
171
+ end
172
+
173
+ slug = base.downcase.gsub(/[^a-z0-9]+/, '-').gsub(/^-|-$/, '')
174
+ slug = slug[0, 40] if slug.length > 40
175
+ slug = "snippet-#{SecureRandom.hex(4)}" if slug.empty?
176
+
177
+ existing_ids = load_data.keys
178
+ candidate = slug
179
+ suffix = 1
180
+ while existing_ids.include?(candidate)
181
+ suffix += 1
182
+ candidate = "#{slug}-#{suffix}"
183
+ end
184
+
185
+ candidate
186
+ end
187
+ end
188
+ end
189
+ end
190
+
191
+
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsConsolePro
4
+ module Snippets
5
+ # Value object representing a filtered/listed set of snippets
6
+ class CollectionResult
7
+ include Enumerable
8
+
9
+ attr_reader :snippets, :query, :tags, :limit, :total_count
10
+
11
+ def initialize(snippets:, query: nil, tags: nil, limit: nil, total_count: nil)
12
+ @snippets = Array(snippets)
13
+ @query = query
14
+ @tags = Array(tags).compact
15
+ @limit = limit
16
+ @total_count = total_count || @snippets.length
17
+ end
18
+
19
+ def each(&block)
20
+ snippets.each(&block)
21
+ end
22
+
23
+ def size
24
+ snippets.size
25
+ end
26
+
27
+ def empty?
28
+ snippets.empty?
29
+ end
30
+
31
+ def metadata
32
+ {
33
+ query: query,
34
+ tags: tags,
35
+ limit: limit,
36
+ total_count: total_count
37
+ }
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+
44
+
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsConsolePro
4
+ module Snippets
5
+ # Value object representing a single snippet lookup or creation
6
+ class SingleResult
7
+ attr_reader :snippet, :action, :created, :message
8
+
9
+ def initialize(snippet:, action: :show, created: false, message: nil)
10
+ @snippet = snippet
11
+ @action = action
12
+ @created = created
13
+ @message = message
14
+ end
15
+
16
+ def created?
17
+ !!created
18
+ end
19
+
20
+ def metadata
21
+ {
22
+ action: action,
23
+ created: created?,
24
+ message: message
25
+ }
26
+ end
27
+ end
28
+ end
29
+ end
30
+
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'time'
4
+
5
+ module RailsConsolePro
6
+ module Snippets
7
+ # Represents a single snippet record persisted to disk
8
+ class Snippet
9
+ attr_reader :id, :body, :tags, :description, :created_at, :updated_at, :favorite, :metadata
10
+
11
+ def initialize(id:, body:, tags: nil, description: nil, created_at: nil, updated_at: nil, favorite: false, metadata: nil)
12
+ @id = normalize_id(id)
13
+ @body = normalize_body(body)
14
+ @tags = normalize_tags(tags)
15
+ @description = description&.strip
16
+ @created_at = normalize_time(created_at)
17
+ @updated_at = normalize_time(updated_at || created_at)
18
+ @favorite = !!favorite
19
+ @metadata = metadata.is_a?(Hash) ? metadata.transform_keys(&:to_sym).freeze : {}.freeze
20
+ @tags_for_search = @tags.map(&:downcase).freeze
21
+ @searchable_values = begin
22
+ values = [@id, @description, @body].compact
23
+ values.concat(@tags_for_search)
24
+ values.map { |val| val.to_s.downcase }.freeze
25
+ end
26
+ freeze
27
+ end
28
+
29
+ def favorite?
30
+ favorite
31
+ end
32
+
33
+ def with(**attributes)
34
+ self.class.new(**to_h.merge(attributes))
35
+ end
36
+
37
+ def matches?(term:, tags: nil)
38
+ matches_term = term.nil? || term.empty? || searchable_values.any? { |value| value.include?(term.downcase) }
39
+ matches_tags =
40
+ if tags.nil? || tags.empty?
41
+ true
42
+ else
43
+ desired_tags = Array(tags).compact.map { |tag| tag.to_s.downcase }.uniq
44
+ snippet_tags = tags_for_search
45
+ desired_tags.all? { |tag| snippet_tags.include?(tag) }
46
+ end
47
+
48
+ matches_term && matches_tags
49
+ end
50
+
51
+ def summary
52
+ first_line = body.lines.first&.strip || ''
53
+ descriptor = description || first_line
54
+ descriptor = descriptor[0..96] + '…' if descriptor && descriptor.length > 97
55
+ descriptor || id
56
+ end
57
+
58
+ def to_h
59
+ {
60
+ id: id,
61
+ body: body,
62
+ tags: tags.dup,
63
+ description: description,
64
+ created_at: created_at,
65
+ updated_at: updated_at,
66
+ favorite: favorite,
67
+ metadata: metadata.dup
68
+ }
69
+ end
70
+
71
+ private
72
+
73
+ def normalize_id(value)
74
+ value.to_s.strip.downcase.gsub(/\s+/, '-')
75
+ end
76
+
77
+ def normalize_body(value)
78
+ body = value.respond_to?(:call) ? value.call.to_s : value.to_s
79
+ raise ArgumentError, 'Snippet body cannot be empty' if body.strip.empty?
80
+ body
81
+ end
82
+
83
+ def normalize_tags(value)
84
+ Array(value).compact.map { |tag| tag.to_s.strip.downcase }.reject(&:empty?).uniq.freeze
85
+ end
86
+
87
+ def normalize_time(value)
88
+ case value
89
+ when Time
90
+ value
91
+ when String
92
+ begin
93
+ Time.parse(value)
94
+ rescue ArgumentError
95
+ Time.now
96
+ end
97
+ else
98
+ Time.now
99
+ end
100
+ end
101
+
102
+ def searchable_values
103
+ @searchable_values
104
+ end
105
+
106
+ def tags_for_search
107
+ @tags_for_search
108
+ end
109
+ end
110
+ end
111
+ end
112
+
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsConsolePro
4
+ module Snippets
5
+ autoload :Snippet, 'rails_console_pro/snippets/snippet'
6
+ autoload :CollectionResult, 'rails_console_pro/snippets/collection_result'
7
+ autoload :SingleResult, 'rails_console_pro/snippets/single_result'
8
+ end
9
+ end
10
+
11
+
12
+
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsConsolePro
4
- VERSION = "0.1.1"
4
+ VERSION = "0.1.3"
5
5
  end
6
6
 
@@ -54,6 +54,6 @@ Gem::Specification.new do |spec|
54
54
  spec.add_development_dependency "rake", "~> 13.0"
55
55
  spec.add_development_dependency "rspec", "~> 3.12"
56
56
  spec.add_development_dependency "rails", "~> 6.0"
57
- spec.add_development_dependency "sqlite3", "~> 2.1"
57
+ spec.add_development_dependency "sqlite3", "~> 1.4"
58
58
  end
59
59
 
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_console_pro
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Harsh
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2025-11-07 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: pastel
@@ -120,14 +119,14 @@ dependencies:
120
119
  requirements:
121
120
  - - "~>"
122
121
  - !ruby/object:Gem::Version
123
- version: '2.1'
122
+ version: '1.4'
124
123
  type: :development
125
124
  prerelease: false
126
125
  version_requirements: !ruby/object:Gem::Requirement
127
126
  requirements:
128
127
  - - "~>"
129
128
  - !ruby/object:Gem::Version
130
- version: '2.1'
129
+ version: '1.4'
131
130
  description: |
132
131
  Rails Console Pro enhances your Rails console with powerful debugging tools:
133
132
  - Beautiful colored formatting for ActiveRecord objects
@@ -160,7 +159,10 @@ files:
160
159
  - docs/FORMATTING.md
161
160
  - docs/MODEL_STATISTICS.md
162
161
  - docs/OBJECT_DIFFING.md
162
+ - docs/PROFILING.md
163
+ - docs/QUEUE_INSIGHTS.md
163
164
  - docs/SCHEMA_INSPECTION.md
165
+ - docs/SNIPPETS.md
164
166
  - docs/SQL_EXPLAIN.md
165
167
  - lib/generators/rails_console_pro/install_generator.rb
166
168
  - lib/generators/rails_console_pro/templates/rails_console_pro.rb
@@ -174,7 +176,10 @@ files:
174
176
  - lib/rails_console_pro/commands/diff_command.rb
175
177
  - lib/rails_console_pro/commands/explain_command.rb
176
178
  - lib/rails_console_pro/commands/export_command.rb
179
+ - lib/rails_console_pro/commands/jobs_command.rb
180
+ - lib/rails_console_pro/commands/profile_command.rb
177
181
  - lib/rails_console_pro/commands/schema_command.rb
182
+ - lib/rails_console_pro/commands/snippets_command.rb
178
183
  - lib/rails_console_pro/commands/stats_command.rb
179
184
  - lib/rails_console_pro/configuration.rb
180
185
  - lib/rails_console_pro/diff_result.rb
@@ -189,11 +194,17 @@ files:
189
194
  - lib/rails_console_pro/printers/collection_printer.rb
190
195
  - lib/rails_console_pro/printers/diff_printer.rb
191
196
  - lib/rails_console_pro/printers/explain_printer.rb
197
+ - lib/rails_console_pro/printers/profile_printer.rb
198
+ - lib/rails_console_pro/printers/queue_insights_printer.rb
192
199
  - lib/rails_console_pro/printers/relation_printer.rb
193
200
  - lib/rails_console_pro/printers/schema_printer.rb
201
+ - lib/rails_console_pro/printers/snippet_collection_printer.rb
202
+ - lib/rails_console_pro/printers/snippet_printer.rb
194
203
  - lib/rails_console_pro/printers/stats_printer.rb
204
+ - lib/rails_console_pro/profile_result.rb
195
205
  - lib/rails_console_pro/pry_commands.rb
196
206
  - lib/rails_console_pro/pry_integration.rb
207
+ - lib/rails_console_pro/queue_insights_result.rb
197
208
  - lib/rails_console_pro/railtie.rb
198
209
  - lib/rails_console_pro/schema_inspector_result.rb
199
210
  - lib/rails_console_pro/serializers/active_record_serializer.rb
@@ -201,13 +212,22 @@ files:
201
212
  - lib/rails_console_pro/serializers/base_serializer.rb
202
213
  - lib/rails_console_pro/serializers/diff_serializer.rb
203
214
  - lib/rails_console_pro/serializers/explain_serializer.rb
215
+ - lib/rails_console_pro/serializers/profile_serializer.rb
204
216
  - lib/rails_console_pro/serializers/relation_serializer.rb
205
217
  - lib/rails_console_pro/serializers/schema_serializer.rb
206
218
  - lib/rails_console_pro/serializers/stats_serializer.rb
207
219
  - lib/rails_console_pro/services/column_stats_calculator.rb
208
220
  - lib/rails_console_pro/services/index_analyzer.rb
221
+ - lib/rails_console_pro/services/profile_collector.rb
222
+ - lib/rails_console_pro/services/queue_action_service.rb
223
+ - lib/rails_console_pro/services/queue_insight_fetcher.rb
224
+ - lib/rails_console_pro/services/snippet_repository.rb
209
225
  - lib/rails_console_pro/services/stats_calculator.rb
210
226
  - lib/rails_console_pro/services/table_size_calculator.rb
227
+ - lib/rails_console_pro/snippets.rb
228
+ - lib/rails_console_pro/snippets/collection_result.rb
229
+ - lib/rails_console_pro/snippets/single_result.rb
230
+ - lib/rails_console_pro/snippets/snippet.rb
211
231
  - lib/rails_console_pro/stats_result.rb
212
232
  - lib/rails_console_pro/version.rb
213
233
  - lib/tasks/rails_console_pro.rake
@@ -219,7 +239,6 @@ metadata:
219
239
  source_code_uri: https://github.com/harshumaretiya/rails_console_pro
220
240
  changelog_uri: https://github.com/harshumaretiya/rails_console_pro/blob/main/CHANGELOG.md
221
241
  rubygems_mfa_required: 'true'
222
- post_install_message:
223
242
  rdoc_options: []
224
243
  require_paths:
225
244
  - lib
@@ -234,8 +253,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
234
253
  - !ruby/object:Gem::Version
235
254
  version: '0'
236
255
  requirements: []
237
- rubygems_version: 3.1.6
238
- signing_key:
256
+ rubygems_version: 3.7.2
239
257
  specification_version: 4
240
258
  summary: Enhanced Rails console with schema inspection, SQL explain, association navigation,
241
259
  and beautiful formatting