You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: _posts/2020-01-23-farewell-rails-autoloading.md
+57-11Lines changed: 57 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,28 +1,72 @@
1
1
---
2
2
layout: post
3
3
author: Tony Schneider
4
-
title : Farewell Rails Autoloading
4
+
title : Classic Rails Autoloading - Eigenclasses
5
5
date : 2020-01-23
6
6
tags : software
7
-
published: false
8
7
---
9
8
9
+
Rails constant autoloading is a really nifty feature.
10
+
11
+
It lets us reference constants without explicitly requiring them.
12
+
It is also what allows Rails to pick up changes to files without having to constantly restart your server.
13
+
14
+
It's one of those features that goes under appreciated.
15
+
If it's working you probably don't even know it's there -- until something goes wrong :laughing:
16
+
17
+
One gotcha I've run into a number of times is how it interacts with Ruby's `class << self` syntax.
18
+
19
+
## 10,000 Foot View
20
+
21
+
When you write Ruby code, you are likely defining lots of constants.
22
+
Module names are constants, class names are constants, and of course constants are constants!
23
+
24
+
When you run the code, Ruby expects you to have defined the constants you use.
25
+
Typically this is done by requiring the ruby file(s) that you plan to use.
26
+
27
+
```ruby
28
+
# in foo.rb
29
+
classFoo
30
+
end
31
+
32
+
# in bar.rb
33
+
require"foo"
34
+
Foo.new
35
+
```
36
+
37
+
If we were to reference `Foo` in `bar.rb` without the `require "foo"`, ruby would call `const_missing`.
38
+
Without any further intervention, it would raise an... uninitialized constant error a la `NameError (uninitialized constant Foo)`
39
+
40
+
Rails autoloading works by hooking into the ruby hook `const_missing` and relying on autoloading _conventions_ to figure out where to find the missing constant.
41
+
10
42
## First some Ruby
11
43
12
-
Rails autoloading works by hooking into the ruby hook const_missing.
13
-
You run some code, Ruby’s like what’s that, rails is like, “I got you, I’ve implemented const_missing” and walks up the module hierarchy and requires the file that constant should be defined in by rails convention.
44
+
```ruby
45
+
classYourClass
46
+
class << self
47
+
defyour_method
48
+
"Hi there"
49
+
end
50
+
end
51
+
end
52
+
53
+
YourClass.your_method # => Hi there
54
+
```
14
55
15
-
However, the`class << self` syntax isn’t simply an alternate syntax for defining class methods.
56
+
The`class << self` syntax isn’t simply an alternate syntax for defining class methods.
16
57
While ultimately it results in a class method, you’re doing so by opening the class’s "eigenclass".
17
-
Eigen just means self in german or whatever.
58
+
59
+
Sounds intimidating, but _Eigen_ just means "self" in German.
18
60
I think it's easier to reason about when referred to as a "singleton class".
19
61
20
62
In the ruby object model you have classes and instances of those classes.
21
-
A user defined class is just an instance of the class Class (whew).
22
-
So, if you're curious you might wonder how ruby keeps track of class methods vs instance methods.
63
+
A user defined class is just an instance of the class Class (whew :sweat_smile:).
23
64
65
+
If you're curious, you might wonder how ruby keeps track of class methods vs instance methods.
24
66
The answer is that each class has an anonymous singleton class.
67
+
25
68
You can actually see it by doing `YourClass.singleton_class`.
69
+
26
70
The class methods you define (regardless of how) end up as instance methods of the singleton class, as opposed to instance methods on the class you defined.
27
71
28
72
```
@@ -44,9 +88,11 @@ class A
44
88
Module.nesting
45
89
end
46
90
end
91
+
47
92
defself.bar
48
93
Module.nesting
49
94
end
95
+
50
96
defbaz
51
97
Module.nesting
52
98
end
@@ -61,7 +107,7 @@ In Rails 5, here is roughly how the "classic" autoloading algorithm works: https
61
107
62
108
So let's go to an example you might see in the wild:
63
109
64
-
```
110
+
```ruby
65
111
moduleSomeEngine
66
112
moduleSomeNamespace
67
113
classPolicyService
@@ -79,7 +125,7 @@ module SomeEngine
79
125
end
80
126
```
81
127
82
-
As defined, the nesting inside `PolicyService.create_policy` is `[#<Class:SomeEngine::SomeNamespace::PolicyService>, SomeEngine::SomeNamespace::PolicyService]`.
128
+
As defined, the nesting inside `PolicyService.create_policy` is:`[#<Class:SomeEngine::SomeNamespace::PolicyService>, SomeEngine::SomeNamespace::PolicyService]`.
83
129
84
130
Same as the earlier example, the nesting for `PolicyService.create_policy2` is `[SomeEngine::SomeNamespace::PolicyService]`.
85
131
You might see where I'm headed ;)
@@ -97,4 +143,4 @@ And you'll get a `NameError` because (let's pretend) `::RatingService` isn't a t
97
143
In the second example, the module nesting is `SomeEngine::SomeNamespace::RatingService`.
98
144
As a result, `PolicyService.create_policy2` works as expected, first checking for `SomeEngine::SomeNamespace::RatingService` then `SomeEngine::RatingService` and finally `::RatingService`.
99
145
100
-
Rails 6 reworks how autoloading is done using a library called Zeitwerk and I'm really excited for it! (https://github.com/fxn/zeitwerk)
146
+
Rails 6 reworks (thankfully :sweat_smile:) how autoloading is done using a library called [Zeitwerk](https://github.com/fxn/zeitwerk) and I'm really excited for it!
0 commit comments