activerecord-minimizer 0.2.0 → 0.3.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 +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +1 -10
- data/lib/ar_minimizer/census.rb +4 -14
- data/lib/ar_minimizer/railtie.rb +0 -2
- data/lib/ar_minimizer/version.rb +1 -1
- data/lib/ar_minimizer.rb +0 -1
- metadata +2 -4
- data/lib/ar_minimizer/enums.rb +0 -61
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b96e595f334bcacd836276d8ff508f885079a41d045ef4ffdcc743689ae6469b
|
|
4
|
+
data.tar.gz: 7ecfa22211db6dc240d50dbc20cdcf99f6e133e8e4ba416e54a477c2b3a6a817
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3cd2f5496af0696ee69d1eea8e49573c5cd3df9668d34fae090746f8b9f86311c7f3c83caca487eecf639dc6d2e33e49d107f41f7b9c73aa216cc5886cf07f0b
|
|
7
|
+
data.tar.gz: 55114753dad4d0ffad49945183424379059bca3637f0d24517e7bcc6d86cf475646bec3d4e2cc499c76b79b3d3ec900555d41d1a2e267237f3b05695d9472428
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0 (2026-11-05)
|
|
4
|
+
|
|
5
|
+
- Removed `config.ar_minimizer.enums` (`ArMinimizer::Enums`). It made enum predicates faster in a benchmark but changed nothing measurable in production, and it no longer worked on Rails main. Setting it does nothing now. `ar_minimizer:census` no longer counts enum methods.
|
|
6
|
+
|
|
3
7
|
## 0.2.0 (2026-10-20)
|
|
4
8
|
|
|
5
9
|
- With `load_time`, the manifest's index (10-20 MB on a large app) is let go once an eager-loading boot is done, before a preloading server forks; a file loaded later indexes the manifest again.
|
data/README.md
CHANGED
|
@@ -56,14 +56,6 @@ first call to one generates it on that model.
|
|
|
56
56
|
Turn `slim` on in development and tests as well as production: the
|
|
57
57
|
errors then show up while you work and in CI. Slim follows code reloads.
|
|
58
58
|
|
|
59
|
-
## Enums
|
|
60
|
-
|
|
61
|
-
`config.ar_minimizer.enums = true` replaces the closures Rails defines for
|
|
62
|
-
enum predicates and bang methods, which build and intern the
|
|
63
|
-
`<name>_for_database` symbol on every call, with ordinary methods carrying
|
|
64
|
-
the enum's values: `def published? = public_send(:status_for_database) == 1`.
|
|
65
|
-
1.3–1.6× faster predicates; non-finite float values keep Rails' closures.
|
|
66
|
-
|
|
67
59
|
## Experimental
|
|
68
60
|
|
|
69
61
|
Each is off unless set. They are faster per call in benchmarks, but made no
|
|
@@ -105,7 +97,7 @@ Where it compiles:
|
|
|
105
97
|
`app/` and `lib/` in place instead, like explode_sqlite. Production only (or
|
|
106
98
|
`FORCE=1`); `DRY_RUN=1` previews.
|
|
107
99
|
|
|
108
|
-
All three read the **manifest** (strict mode
|
|
100
|
+
All three read the **manifest** (strict mode doesn't need one), `config/ar_minimizer.json`, written by
|
|
109
101
|
`bin/rails ar_minimizer:manifest`: per model its columns and their query kind,
|
|
110
102
|
the attribute method patterns, hand-written methods, superclass, app modules,
|
|
111
103
|
associations, scopes, and names it defines another way (an enum predicate
|
|
@@ -154,7 +146,6 @@ without, the same traffic for an hour, October 2026):
|
|
|
154
146
|
| part | result |
|
|
155
147
|
|---|---|
|
|
156
148
|
| strict mode | no call to a removed method; the same latency and memory |
|
|
157
|
-
| enums | the same median latency; no change in allocations on these pages |
|
|
158
149
|
| small records | no difference: tens of records per request |
|
|
159
150
|
| compiling in views | no faster, ~22 MB more per worker |
|
|
160
151
|
| compiling at load time | ~12% more CPU per request, not reproduced locally; measured before the app was preloaded, so worth measuring again |
|
data/lib/ar_minimizer/census.rb
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module ArMinimizer
|
|
4
|
-
# What the attribute-method
|
|
4
|
+
# What the attribute-method compilers cover in an app.
|
|
5
5
|
module Census
|
|
6
|
-
Result = Data.define(:models, :columns, :stock_methods, :generated_methods, :
|
|
7
|
-
:sites, :files, :manifest) do
|
|
6
|
+
Result = Data.define(:models, :columns, :stock_methods, :generated_methods, :sites, :files, :manifest) do
|
|
8
7
|
def lines(verbose: false)
|
|
9
8
|
[
|
|
10
9
|
"models: #{models}, #{columns} columns",
|
|
11
10
|
"attribute methods: #{stock_methods} in stock Rails, #{generated_methods || "n/a (slim off)"} generated with slim",
|
|
12
|
-
"enum methods: #{enum_compiled}/#{enum_methods} compiled",
|
|
13
11
|
"attribute call sites: #{sites} compilable in #{files} files under app/ and lib/",
|
|
14
12
|
"manifest: #{manifest}",
|
|
15
13
|
]
|
|
@@ -24,22 +22,14 @@ module ArMinimizer
|
|
|
24
22
|
models.each(&:define_attribute_methods)
|
|
25
23
|
models.sum { it.send(:generated_attribute_methods).instance_methods(false).size }
|
|
26
24
|
end
|
|
27
|
-
enum_methods = enum_compiled = 0
|
|
28
|
-
models.each do |model|
|
|
29
|
-
mod = model.instance_variable_get(:@_enum_methods_module) or next
|
|
30
|
-
mod.instance_methods(false).each do |name|
|
|
31
|
-
enum_methods += 1
|
|
32
|
-
enum_compiled += 1 if mod.instance_method(name).source_location&.first.to_s.start_with?("enum ")
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
25
|
sites = files = 0
|
|
36
26
|
Dir.glob(File.join(root.to_s, "{app,lib}", "**", "*.rb")).each do |file|
|
|
37
27
|
n = Rewriter.new(index: index, path: file, guards: guards).rewrite(File.read(file)).sites
|
|
38
28
|
sites += n
|
|
39
29
|
files += 1 if n.positive?
|
|
40
30
|
end
|
|
41
|
-
Result.new(models.size, models.sum { it.attribute_names.size }, stock, generated,
|
|
42
|
-
|
|
31
|
+
Result.new(models.size, models.sum { it.attribute_names.size }, stock, generated, sites, files,
|
|
32
|
+
manifest_state(root, index))
|
|
43
33
|
end
|
|
44
34
|
|
|
45
35
|
def self.manifest_state(root, index)
|
data/lib/ar_minimizer/railtie.rb
CHANGED
|
@@ -10,7 +10,6 @@ module ArMinimizer
|
|
|
10
10
|
# config.ar_minimizer.strict = false # ... and generate the rest when first called, instead of removing them
|
|
11
11
|
# config.ar_minimizer.load_time = true # compile app/ and lib/ as they load (needs the manifest)
|
|
12
12
|
# config.ar_minimizer.views = true # compile templates as ActionView loads them
|
|
13
|
-
# config.ar_minimizer.enums = true # enum predicates/bang methods as plain methods
|
|
14
13
|
# config.ar_minimizer.small_records = true # no Hashes for records that never fill them
|
|
15
14
|
# config.ar_minimizer.guards = true # also compile calls on receivers of unknown class, behind a class check
|
|
16
15
|
#
|
|
@@ -30,7 +29,6 @@ module ArMinimizer
|
|
|
30
29
|
manifest = -> { ArMinimizer::Manifest.parse(manifest_json) } if manifest_json
|
|
31
30
|
|
|
32
31
|
ActiveSupport.on_load(:active_record) do
|
|
33
|
-
ArMinimizer::Enums.install! if options.enums
|
|
34
32
|
ArMinimizer::SmallRecords.install! if options.small_records
|
|
35
33
|
ArMinimizer::Slim.enable!(keep_methods: keep_methods, strict: options.strict != false) if options.slim
|
|
36
34
|
ArMinimizer::Profile.start!(ENV["AR_MINIMIZER_PROFILE"]) if ENV["AR_MINIMIZER_PROFILE"]
|
data/lib/ar_minimizer/version.rb
CHANGED
data/lib/ar_minimizer.rb
CHANGED
|
@@ -25,7 +25,6 @@ module ArMinimizer
|
|
|
25
25
|
autoload :Views, "ar_minimizer/views"
|
|
26
26
|
autoload :Profile, "ar_minimizer/profile"
|
|
27
27
|
autoload :Manifest, "ar_minimizer/manifest"
|
|
28
|
-
autoload :Enums, "ar_minimizer/enums"
|
|
29
28
|
autoload :Census, "ar_minimizer/census"
|
|
30
29
|
autoload :SmallRecords, "ar_minimizer/small_records"
|
|
31
30
|
autoload :Loader, "ar_minimizer/loader"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: activerecord-minimizer
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sampo Kuokkanen
|
|
@@ -59,8 +59,7 @@ dependencies:
|
|
|
59
59
|
version: '0.4'
|
|
60
60
|
description: Generates only the reader and writer per Active Record column (strict
|
|
61
61
|
mode removes the other 19 attribute methods), compiles call sites to the calls those
|
|
62
|
-
methods stood for
|
|
63
|
-
Hashes they never fill.
|
|
62
|
+
methods stood for and stops records allocating Hashes they never fill.
|
|
64
63
|
executables: []
|
|
65
64
|
extensions: []
|
|
66
65
|
extra_rdoc_files: []
|
|
@@ -72,7 +71,6 @@ files:
|
|
|
72
71
|
- lib/ar_minimizer.rb
|
|
73
72
|
- lib/ar_minimizer/build.rb
|
|
74
73
|
- lib/ar_minimizer/census.rb
|
|
75
|
-
- lib/ar_minimizer/enums.rb
|
|
76
74
|
- lib/ar_minimizer/index.rb
|
|
77
75
|
- lib/ar_minimizer/loader.rb
|
|
78
76
|
- lib/ar_minimizer/manifest.rb
|
data/lib/ar_minimizer/enums.rb
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module ArMinimizer
|
|
4
|
-
# Enum predicates and bang methods as ordinary methods.
|
|
5
|
-
#
|
|
6
|
-
# Rails defines them with closures, and each predicate call builds and
|
|
7
|
-
# interns the `<name>_for_database` symbol before calling it:
|
|
8
|
-
#
|
|
9
|
-
# # def active?() status_for_database == 0 end (Rails' own comment)
|
|
10
|
-
# define_method("#{value_method_name}?") { public_send(:"#{name}_for_database") == value }
|
|
11
|
-
#
|
|
12
|
-
# Here the enum's literal data goes into the method source instead, as
|
|
13
|
-
# Roundhouse does for macros with literal arguments:
|
|
14
|
-
#
|
|
15
|
-
# def active? = public_send(:status_for_database) == 0
|
|
16
|
-
# def active! = update!("status" => 0)
|
|
17
|
-
#
|
|
18
|
-
# Rails still runs first (conflict detection, scopes); only the two methods
|
|
19
|
-
# are replaced. Rails allows booleans, integers, floats, symbols and strings
|
|
20
|
-
# as values; non-finite floats, and method names that aren't plain
|
|
21
|
-
# identifiers, keep Rails' closures.
|
|
22
|
-
module Enums
|
|
23
|
-
IDENTIFIER = /\A[a-zA-Z_][a-zA-Z0-9_]*\z/
|
|
24
|
-
|
|
25
|
-
class << self
|
|
26
|
-
# Before models load (their class bodies declare the enums).
|
|
27
|
-
def install!
|
|
28
|
-
@enabled = true
|
|
29
|
-
mod = ActiveRecord::Enum.const_get(:EnumMethods)
|
|
30
|
-
mod.prepend(Definer) unless mod < Definer
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def disable! = @enabled = false
|
|
34
|
-
|
|
35
|
-
def enabled? = @enabled == true
|
|
36
|
-
|
|
37
|
-
def literal(value)
|
|
38
|
-
case value
|
|
39
|
-
when Integer, String, Symbol, true, false, nil then value.inspect
|
|
40
|
-
when Float then value.inspect if value.finite?
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
module Definer
|
|
46
|
-
private
|
|
47
|
-
|
|
48
|
-
def define_enum_methods(name, value_method_name, value, scopes, instance_methods)
|
|
49
|
-
super
|
|
50
|
-
return unless instance_methods && Enums.enabled?
|
|
51
|
-
return unless value_method_name.match?(IDENTIFIER) && (literal = Enums.literal(value))
|
|
52
|
-
|
|
53
|
-
remove_method(:"#{value_method_name}?", :"#{value_method_name}!")
|
|
54
|
-
module_eval(<<~RUBY, "enum #{klass.name}.#{name}", 1)
|
|
55
|
-
def #{value_method_name}? = public_send(#{:"#{name}_for_database".inspect}) == #{literal}
|
|
56
|
-
def #{value_method_name}! = update!(#{name.inspect} => #{literal})
|
|
57
|
-
RUBY
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
end
|