lazy_names 1.0.0 → 2.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d0507f34b2f1f59a72734ddeb41c5b867f5114fd117ba73baa33293b46773d05
4
- data.tar.gz: 3d9e34b1beeba0a4ef3ac8b87e3faf295614efcee1da770d40ee5f5619c9752e
3
+ metadata.gz: 4d4b509d7cf80a3a06d081c317071cd6fbe5108f86f4e5e3c73b6ad04919be47
4
+ data.tar.gz: c975ba3dba6e0c88ed1277e757284a1f98599b2387264285765451150efeb1b2
5
5
  SHA512:
6
- metadata.gz: 26231616eaa3a461ff281553300503d678952a3e4957593473b7db00fa00454848a6fa1cf4071de52d2e04b4afd4030ccd27c5988e69b17606ef3a027973481c
7
- data.tar.gz: 81f910b280c65f62d9316a34b67d932950d991ba13a4dea3df18dcf78b8459d5745581d9422b1078eed624336e3a88985a4741710785530ee50aa9e79934f067
6
+ metadata.gz: 92841fbe989e3f7556d9dd1269f35bff70fc78b8f9b75762011f37d7510bda072f9d63e21fa23c427d968ae657acfb2241aeeef7cb29c8f0b7cc271447cb0ca6
7
+ data.tar.gz: d8d5b5031d35521f754bc9c27dd9db7af016a6a347bac8c0b777039094a33e6a9e76005879fb1806ae7e25c4c3a2cacccd2bdcfcd9b93c058ee523be31ca7dee
@@ -9,7 +9,7 @@ jobs:
9
9
  timeout-minutes: 15
10
10
  runs-on: ubuntu-24.04
11
11
  steps:
12
- - uses: actions/checkout@v4
12
+ - uses: actions/checkout@v6
13
13
  - uses: ruby/setup-ruby@v1
14
14
  with:
15
15
  ruby-version: 3.1
@@ -55,7 +55,7 @@ jobs:
55
55
  # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
56
56
  steps:
57
57
  - name: Checkout repository
58
- uses: actions/checkout@v4
58
+ uses: actions/checkout@v6
59
59
 
60
60
  # Add any setup steps before running the `github/codeql-action/init` action.
61
61
  # This includes steps like installing compilers or runtimes (`actions/setup-node`
@@ -65,7 +65,7 @@ jobs:
65
65
 
66
66
  # Initializes the CodeQL tools for scanning.
67
67
  - name: Initialize CodeQL
68
- uses: github/codeql-action/init@v3
68
+ uses: github/codeql-action/init@v4
69
69
  with:
70
70
  languages: ${{ matrix.language }}
71
71
  build-mode: ${{ matrix.build-mode }}
@@ -93,6 +93,6 @@ jobs:
93
93
  exit 1
94
94
 
95
95
  - name: Perform CodeQL Analysis
96
- uses: github/codeql-action/analyze@v3
96
+ uses: github/codeql-action/analyze@v4
97
97
  with:
98
98
  category: "/language:${{matrix.language}}"
@@ -14,7 +14,7 @@ jobs:
14
14
  os: [ ubuntu-latest, macos-latest, windows-latest ]
15
15
  runs-on: ${{ matrix.os }}
16
16
  steps:
17
- - uses: actions/checkout@v4
17
+ - uses: actions/checkout@v6
18
18
  - uses: ruby/setup-ruby@v1
19
19
  with:
20
20
  ruby-version: '3.1'
data/.lazy_names.tt.rb ADDED
@@ -0,0 +1,5 @@
1
+ # project specific
2
+ MUCC = Models::Users::CreditCard
3
+
4
+ # global
5
+ ARBase = ActiveRecord::Base
data/.rubocop.yml CHANGED
@@ -37,5 +37,43 @@ Metrics/BlockLength:
37
37
  Exclude:
38
38
  - spec/**/*.rb
39
39
 
40
+ Metrics/MethodLength:
41
+ Max: 15
42
+
43
+ Metrics/AbcSize:
44
+ Max: 20
45
+
40
46
  RSpec/NestedGroups:
41
47
  Enabled: false
48
+
49
+ RSpec/MultipleExpectations:
50
+ Max: 5
51
+
52
+ RSpec/ExampleLength:
53
+ Max: 20
54
+
55
+ RSpec/MessageSpies:
56
+ Enabled: false
57
+
58
+ RSpec/RemoveConst:
59
+ Enabled: false
60
+
61
+ RSpec/InstanceVariable:
62
+ Enabled: false
63
+
64
+ RSpec/DescribeClass:
65
+ Enabled: false
66
+
67
+ RSpec/ContextWording:
68
+ Enabled: false
69
+
70
+ RSpec/AnyInstance:
71
+ Enabled: false
72
+
73
+ Security/Eval:
74
+ Exclude:
75
+ - spec/**/*.rb
76
+
77
+ Style/FrozenStringLiteralComment:
78
+ Exclude:
79
+ - .lazy_names.tt.rb
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- lazy_names (1.0.0)
4
+ lazy_names (2.0.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -10,7 +10,7 @@ GEM
10
10
  coderay (1.1.3)
11
11
  diff-lcs (1.5.1)
12
12
  docile (1.4.1)
13
- json (2.10.1)
13
+ json (2.10.2)
14
14
  language_server-protocol (3.17.0.4)
15
15
  lint_roller (1.1.0)
16
16
  method_source (1.1.0)
@@ -0,0 +1,276 @@
1
+ # Migration Guide: v1.x to v2.0
2
+
3
+ This guide will help you migrate from LazyNames v1.x (YAML configuration) to v2.0 (Ruby configuration).
4
+
5
+ ## Overview
6
+
7
+ LazyNames v2.0 removes YAML support in favor of plain Ruby configuration files. This change makes the gem more intuitive and Ruby-native.
8
+
9
+ ## Why the Change?
10
+
11
+ As discussed in the original issue, `.irbrc` and `.pryrc` already support plain Ruby. The YAML abstraction was unnecessary when you can simply write:
12
+
13
+ ```ruby
14
+ MUCC = Models::Users::CreditCard
15
+ ```
16
+
17
+ Instead of:
18
+
19
+ ```yaml
20
+ ---
21
+ definitions:
22
+ 'Models::Users::CreditCard': 'MUCC'
23
+ ```
24
+
25
+ ## Breaking Changes
26
+
27
+ - ❌ `.lazy_names.yml` is no longer supported
28
+ - ✅ You must use `.lazy_names.rb` instead
29
+ - ✅ Constants are validated at load time (mandatory)
30
+
31
+ ## Quick Conversion
32
+
33
+ ### Before (v1.x)
34
+
35
+ **.lazy_names.yml**:
36
+ ```yaml
37
+ ---
38
+ definitions:
39
+ 'Models::User': 'MU'
40
+ 'Services::EmailSender': 'SES'
41
+ 'Controllers::API::V1::UsersController': 'CAVUC'
42
+ ```
43
+
44
+ ### After (v2.0)
45
+
46
+ **.lazy_names.rb**:
47
+ ```ruby
48
+ MU = Models::User
49
+ SES = Services::EmailSender
50
+ CAVUC = Controllers::API::V1::UsersController
51
+ ```
52
+
53
+ ## Automated Conversion Script
54
+
55
+ Save this as `convert_to_v2.rb` and run it in your project directory:
56
+
57
+ ```ruby
58
+ #!/usr/bin/env ruby
59
+ require 'yaml'
60
+
61
+ yaml = YAML.load_file('.lazy_names.yml')
62
+ definitions = yaml['definitions'] || yaml.values.first['definitions']
63
+
64
+ File.open('.lazy_names.rb', 'w') do |f|
65
+ f.puts "# Converted from .lazy_names.yml"
66
+ definitions.each do |full, short|
67
+ f.puts "#{short} = #{full}"
68
+ end
69
+ end
70
+
71
+ puts "✓ Converted to .lazy_names.rb"
72
+ ```
73
+
74
+ ### Using the Conversion Script
75
+
76
+ 1. Run the script in your project directory:
77
+ ```bash
78
+ ruby convert_to_v2.rb
79
+ ```
80
+
81
+ 2. Review the generated `.lazy_names.rb`:
82
+ ```bash
83
+ cat .lazy_names.rb
84
+ ```
85
+
86
+ 3. Test it in your console:
87
+ ```bash
88
+ bundle exec rails c
89
+ # or
90
+ bin/console
91
+ ```
92
+
93
+ 4. Once verified, delete the old YAML file:
94
+ ```bash
95
+ rm .lazy_names.yml
96
+ ```
97
+
98
+ ## Global Configuration Migration
99
+
100
+ If you have a global configuration in `~/.lazy_names.yml` with namespace/project scoping:
101
+
102
+ ### Before
103
+
104
+ **~/.lazy_names.yml**:
105
+ ```yaml
106
+ ---
107
+ my_project:
108
+ definitions:
109
+ 'Models::User': 'MU'
110
+ another_project:
111
+ definitions:
112
+ 'API::Client': 'AC'
113
+ ```
114
+
115
+ ### Namespace Scoping Is Intentionally Removed
116
+
117
+ v2.0 **does not support** namespace/project scoping in global config files. This was a deliberate decision:
118
+
119
+ - **It was YAML-induced complexity.** YAML encourages nested structures, but Ruby doesn't need this abstraction.
120
+ - **Project detection is fragile.** Matching project names to directories adds magic that can break.
121
+ - **Project-specific files are better.** Each project having its own `.lazy_names.rb` is more explicit and maintainable.
122
+
123
+ ### After: Use Project-Specific Files (Recommended)
124
+
125
+ **This is the preferred migration path.** Create `.lazy_names.rb` in each project directory:
126
+
127
+ ```ruby
128
+ # my_project/.lazy_names.rb
129
+ MU = Models::User
130
+ ```
131
+
132
+ ```ruby
133
+ # another_project/.lazy_names.rb
134
+ AC = API::Client
135
+ ```
136
+
137
+ Benefits:
138
+ - Version controlled with each project
139
+ - Explicit about what's loaded
140
+ - No surprises or magic detection
141
+ - Easy to understand and maintain
142
+
143
+ ### Alternative: Global File with Guards
144
+
145
+ If you prefer a single global file, use `if defined?()` guards:
146
+
147
+ **~/.lazy_names.rb**:
148
+ ```ruby
149
+ # Only defined if the constant exists in the current project
150
+ MU = Models::User if defined?(Models::User)
151
+ AC = API::Client if defined?(API::Client)
152
+ ```
153
+
154
+ This achieves the same result as namespace scoping but is simpler and more transparent.
155
+
156
+ ## New Features in v2.0
157
+
158
+ ### Validation
159
+
160
+ All constants are now validated before being defined:
161
+
162
+ ```ruby
163
+ # Valid - will be defined
164
+ MU = Models::User
165
+
166
+ # Invalid - will show warning and skip
167
+ INVALID = NonExistent::Class
168
+ # Warning: Line 4: Constant NonExistent::Class not found - INVALID = NonExistent::Class
169
+ ```
170
+
171
+ ### Comments and Formatting
172
+
173
+ ```ruby
174
+ # You can add comments to document your shortcuts
175
+ MU = Models::User
176
+
177
+ # Blank lines are allowed for organization
178
+
179
+ SES = Services::EmailSender
180
+
181
+ # Underscores and numbers work too
182
+ API_V1 = API::V1
183
+ CACHE2 = Cache::RedisCache
184
+ ```
185
+
186
+ ### Better Error Messages
187
+
188
+ v2.0 provides detailed error messages with line numbers:
189
+
190
+ ```
191
+ Loading definitions from /path/to/.lazy_names.rb
192
+ Line 5: Constant Foo::Bar not found - FB = Foo::Bar
193
+ Loaded 10 definitions
194
+ Skipped 1 invalid lines
195
+ ```
196
+
197
+ ## Troubleshooting
198
+
199
+ ### "Constant not found" warnings
200
+
201
+ If you see warnings about constants not being found:
202
+
203
+ 1. **Make sure the constant exists** in your application
204
+ 2. **Check the spelling** - constant names are case-sensitive
205
+ 3. **Ensure the constant is loaded** before LazyNames runs
206
+
207
+ Example:
208
+ ```ruby
209
+ # This will fail if Models isn't loaded yet
210
+ MU = Models::User
211
+
212
+ # This is safer - only define if it exists
213
+ MU = Models::User if defined?(Models::User)
214
+ ```
215
+
216
+ ### Constants not defined in console
217
+
218
+ If constants aren't showing up in your console:
219
+
220
+ 1. Check that `.lazy_names.rb` is in the right location:
221
+ - Project root: `./.lazy_names.rb`
222
+ - Home directory: `~/.lazy_names.rb`
223
+
224
+ 2. Verify your IRB/Pry configuration is correct:
225
+
226
+ **For Pry** (`~/.pryrc` or `.pryrc`):
227
+ ```ruby
228
+ if defined?(LazyNames)
229
+ Pry.config.hooks.add_hook(:when_started, :lazy_names) do
230
+ LazyNames.load_definitions!
231
+ end
232
+ end
233
+ ```
234
+
235
+ **For IRB** (`~/.irbrc` or `.irbrc`):
236
+ ```ruby
237
+ if defined?(LazyNames)
238
+ LazyNames.load_definitions!
239
+ end
240
+ ```
241
+
242
+ 3. Make sure you've updated to v2.0:
243
+ ```bash
244
+ bundle update lazy_names
245
+ ```
246
+
247
+ ### Migration script errors
248
+
249
+ If the conversion script fails:
250
+
251
+ **Error: No .lazy_names.yml found**
252
+ - Make sure you're in the correct directory
253
+ - Check if the file is named exactly `.lazy_names.yml`
254
+
255
+ **Error: .lazy_names.rb already exists**
256
+ - Review the existing file
257
+ - Delete it if you want to regenerate: `rm .lazy_names.rb`
258
+ - Or merge manually
259
+
260
+ ## Need Help?
261
+
262
+ If you encounter issues during migration:
263
+
264
+ 1. Check the [README](README.md) for configuration examples
265
+ 2. Review the [implementation plan](MIGRATION_PLAN_V2.md) for technical details
266
+ 3. Open an issue on [GitHub](https://github.com/zhisme/lazy_names/issues)
267
+
268
+ ## Benefits of v2.0
269
+
270
+ After migrating, you'll enjoy:
271
+
272
+ - ✅ **More intuitive** - Same syntax as `.irbrc`/`.pryrc`
273
+ - ✅ **Better IDE support** - Syntax highlighting and autocomplete
274
+ - ✅ **Mandatory validation** - Know immediately if a constant doesn't exist
275
+ - ✅ **Simpler** - No YAML parsing overhead
276
+ - ✅ **Ruby-native** - Write Ruby to configure Ruby
data/README.md CHANGED
@@ -17,6 +17,16 @@ Consider this example from pry terminal session.
17
17
 
18
18
  The idea is to reduce typing of long namespaced constants to shorter versions. It's very useful when you have a lot of nested namespaces and you need to access them frequently. This gem will take your responsibility to redefine constants to shorter versions and making constant/classes validations.
19
19
 
20
+ ## Why Plain Ruby? (v2.0+)
21
+
22
+ LazyNames v2.0 uses plain Ruby instead of YAML because:
23
+
24
+ - ✅ **Intuitive**: Same syntax you'd write in `.irbrc`/`.pryrc`
25
+ - ✅ **IDE Support**: Syntax highlighting and autocomplete work out of the box
26
+ - ✅ **Validation**: Constants are validated at load time
27
+ - ✅ **Simpler**: No YAML parsing, no extra abstraction
28
+ - ✅ **Ruby-native**: Write Ruby to configure Ruby
29
+
20
30
  ## Installation
21
31
 
22
32
  1. Add this line to your application's Gemfile:
@@ -53,7 +63,9 @@ bundle
53
63
 
54
64
  4. Create your own lazy_names config where you define constants
55
65
  ```bash
56
- cp .lazy_names.tt.yml ~/.lazy_names.yml
66
+ touch ~/.lazy_names.rb
67
+ # or for project-specific config
68
+ touch .lazy_names.rb
57
69
  ```
58
70
 
59
71
  5. Login into your rails or non-rails console
@@ -64,57 +76,93 @@ $ bundle exec rails c # or bin/console
64
76
 
65
77
  ## Configuration
66
78
 
67
- ### Global definition
79
+ Create a `.lazy_names.rb` file in your project root or home directory:
80
+
81
+ ```ruby
82
+ # .lazy_names.rb
83
+ MUCC = Models::Users::CreditCard
84
+ SPP = Services::PaymentProcessor
85
+ CAVUC = Controllers::API::V1::UsersController
86
+ ```
87
+
88
+ ### File Lookup Priority
89
+
90
+ LazyNames looks for configuration in this order:
68
91
 
69
- Take a look onto `lazy_names.tt.yml` it has very basic template for you to start.
92
+ 1. `./.lazy_names.rb` (project-specific) **recommended**
93
+ 2. `~/.lazy_names.rb` (global fallback)
70
94
 
71
- ```yml
72
- ---
73
- my_awesome_project:
74
- definitions:
75
- 'Models::Users::CreditCard': 'MUCC'
95
+ ### Project-Specific Configuration (Recommended)
96
+
97
+ **This is the preferred approach.** Create `.lazy_names.rb` in your project root:
98
+
99
+ ```ruby
100
+ # myproject/.lazy_names.rb
101
+ MUCC = Models::Users::CreditCard
102
+ SPP = Services::PaymentProcessor
76
103
  ```
77
- `my_awesome_project` should be you project/folder name
78
104
 
79
- So consider this example:
105
+ Why project-specific files are better:
106
+ - Version controlled with your project (or gitignored for personal shortcuts)
107
+ - Explicit about what's loaded — no surprises
108
+ - Each project has exactly the shortcuts it needs
109
+ - No conflicts between projects
110
+
111
+ Don't forget to add it to `.gitignore` if you don't want to share:
80
112
  ```sh
81
- $ pwd
82
- /Users/name/my_awesome_project
83
- ```
84
- The last folder name of you ruby project must match the same one in your configuration.
85
- After **definitions** sections you can actually redefine your long constants.
86
- So in this example `Models::Users::CreditCard` is your real project constant and
87
- `MUCC` will be your short variant of it, so you can access `Models::Users::CreditCard`
88
- from `MUCC`. `MUCC` and any other right hand side can be any value, you define the best-suitable names.
89
-
90
- You can define as many constants as you want. The same rule applies for projects.
91
- Your config can have multiple constant definitions per namespace.
92
- ```yml
93
- ---
94
- my_awesome_project:
95
- definitions:
96
- 'Models::Users::CreditCard': 'MUCC'
97
- my_another_project:
98
- definitions:
99
- 'OtherLongConst': 'Short'
113
+ echo '.lazy_names.rb' >> .gitignore
100
114
  ```
101
115
 
102
- ### Project definitions
116
+ ### Global Configuration
103
117
 
104
- In the meantime you can put your `.lazy_names.yml` config directly to project folder, it will be looked up firstly from project.
105
- Just do not forget to put in your `.gitignore`. I believe every developer defines shorter versions of constants by his own opinion.
106
- ```sh
107
- echo '.lazy_names.yml' >> .gitignore
118
+ For shortcuts that work across multiple projects, create `~/.lazy_names.rb` in your home directory.
119
+
120
+ **Important:** Use `if defined?()` guards since constants vary between projects:
121
+
122
+ ```ruby
123
+ # ~/.lazy_names.rb
124
+ # Generic Rails shortcuts (usually available)
125
+ AR = ActiveRecord if defined?(ActiveRecord)
126
+ AM = ActionMailer if defined?(ActionMailer)
127
+
128
+ # Only defined if these exist in the current project
129
+ MU = Models::User if defined?(Models::User)
108
130
  ```
109
- If project folder doesn't contain any `.lazy_names.yml`, it will fallback to home directory.
110
131
 
111
- Configuration per project a bit different: you don't need to specify global scope `my_awesome_project`, you can skip forward to definitions
112
- ```yml
113
- ---
114
- definitions:
115
- 'Models::Users::CreditCard: 'MUCC'
132
+ **Note:** v2.0 intentionally removed namespace/project scoping that existed in v1.x YAML configs. The `if defined?()` pattern is simpler and achieves the same result without magic.
133
+
134
+ ### Validation
135
+
136
+ LazyNames validates each line:
137
+
138
+ - ✅ Must be a constant assignment: `SHORT = Full::Constant::Path`
139
+ - ✅ Constant must exist in your application
140
+ - ⚠️ Invalid lines are skipped with a warning
141
+
142
+ ### Examples
143
+
144
+ ```ruby
145
+ # Comments are allowed
146
+ MUCC = Models::Users::CreditCard
147
+
148
+ # Blank lines are fine
149
+
150
+ SPP = Services::PaymentProcessor
151
+
152
+ # Underscores and numbers in short names
153
+ API_V1 = API::V1
154
+ CACHE2 = Cache::RedisCache
116
155
  ```
117
- Example config can be found in `.lazy_names.tt.project.yml`
156
+
157
+ ## Migrating from v1.x to v2.0
158
+
159
+ LazyNames v2.0 removes YAML support in favor of plain Ruby configuration.
160
+
161
+ **Upgrading from v1.x?** See the complete [Migration Guide](MIGRATION_FROM_V1.md) for:
162
+ - Automated conversion script
163
+ - Step-by-step instructions
164
+ - Troubleshooting tips
165
+ - New features in v2.0
118
166
 
119
167
  ## Development
120
168
 
data/bin/convert_to_v2 ADDED
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'yaml'
5
+
6
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
7
+ def convert_yaml_to_ruby
8
+ yaml_file = '.lazy_names.yml'
9
+ ruby_file = '.lazy_names.rb'
10
+
11
+ unless File.exist?(yaml_file)
12
+ puts "No #{yaml_file} found in current directory"
13
+ exit 1
14
+ end
15
+
16
+ if File.exist?(ruby_file)
17
+ puts "#{ruby_file} already exists. Remove it first or merge manually."
18
+ exit 1
19
+ end
20
+
21
+ begin
22
+ yaml = YAML.load_file(yaml_file)
23
+ definitions = extract_definitions(yaml)
24
+
25
+ if definitions.empty?
26
+ puts "No definitions found in #{yaml_file}"
27
+ exit 1
28
+ end
29
+
30
+ File.open(ruby_file, 'w') do |f|
31
+ f.puts '# Converted from .lazy_names.yml'
32
+ f.puts ''
33
+ definitions.each do |full, short|
34
+ f.puts "#{short} = #{full}"
35
+ end
36
+ end
37
+
38
+ puts "✓ Converted #{definitions.size} definitions to #{ruby_file}"
39
+ puts ''
40
+ puts 'Next steps:'
41
+ puts " 1. Review #{ruby_file}"
42
+ puts " 2. Delete #{yaml_file}"
43
+ puts ' 3. Update lazy_names gem to v2.0'
44
+ rescue StandardError => e
45
+ puts "Error: #{e.message}"
46
+ exit 1
47
+ end
48
+ end
49
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
50
+
51
+ def extract_definitions(yaml)
52
+ if yaml['definitions']
53
+ yaml['definitions']
54
+ elsif yaml.is_a?(Hash) && yaml.values.first.is_a?(Hash)
55
+ yaml.values.first['definitions'] || {}
56
+ else
57
+ {}
58
+ end
59
+ end
60
+
61
+ convert_yaml_to_ruby
data/lazy_names.gemspec CHANGED
@@ -11,10 +11,10 @@ Gem::Specification.new do |spec|
11
11
  spec.email = ['evdev34@gmail.com']
12
12
 
13
13
  spec.description = <<~DESC
14
- lazy_names is ruby programmer friend. You can save your time not typing long
15
- error-phone constants/classes but defining short and nice versions of them.
14
+ lazy_names is ruby programmer friend. Define short aliases for long constant names using plain Ruby.
15
+ Save your time not typing long constants/classes by defining short and intuitive versions of them.
16
16
  DESC
17
- spec.summary = 'Define short constants to frequently used classes/constants'
17
+ spec.summary = 'Define short aliases for long constant names using plain Ruby'
18
18
  spec.homepage = 'https://github.com/zhisme/lazy_names'
19
19
  spec.license = 'MIT'
20
20
 
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LazyNames
4
+ class LineValidator
5
+ ASSIGNMENT_PATTERN = /\A\s*([A-Z][A-Z0-9_]*)\s*=\s*([A-Z][A-Za-z0-9_:]*)\s*\z/.freeze
6
+
7
+ class ValidationResult
8
+ attr_reader :valid, :short_name, :full_constant, :error
9
+
10
+ def initialize(valid:, short_name: nil, full_constant: nil, error: nil)
11
+ @valid = valid
12
+ @short_name = short_name
13
+ @full_constant = full_constant
14
+ @error = error
15
+ end
16
+
17
+ def valid?
18
+ @valid
19
+ end
20
+ end
21
+
22
+ def self.validate(line)
23
+ return skip_result if skip_line?(line)
24
+
25
+ match = line.match(ASSIGNMENT_PATTERN)
26
+ return invalid_result('Invalid syntax') unless match
27
+
28
+ short_name = match[1]
29
+ full_constant = match[2]
30
+
31
+ return invalid_result("Constant #{full_constant} not found") unless constant_exists?(full_constant)
32
+
33
+ ValidationResult.new(
34
+ valid: true,
35
+ short_name: short_name,
36
+ full_constant: full_constant
37
+ )
38
+ end
39
+
40
+ def self.skip_line?(line)
41
+ line.strip.empty? || line.strip.start_with?('#')
42
+ end
43
+
44
+ def self.constant_exists?(constant_path)
45
+ Object.const_get(constant_path)
46
+ true
47
+ rescue NameError
48
+ false
49
+ end
50
+
51
+ def self.skip_result
52
+ ValidationResult.new(valid: false)
53
+ end
54
+
55
+ def self.invalid_result(error)
56
+ ValidationResult.new(valid: false, error: error)
57
+ end
58
+
59
+ private_class_method :skip_line?, :constant_exists?, :skip_result, :invalid_result
60
+ end
61
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LazyNames
4
+ class RubyLoader
5
+ CONFIG_FILE = '.lazy_names.rb'
6
+
7
+ def self.load!(binding)
8
+ new.load!(binding)
9
+ end
10
+
11
+ def initialize
12
+ @loaded_count = 0
13
+ @skipped_count = 0
14
+ @error_count = 0
15
+ end
16
+
17
+ def load!(binding)
18
+ path = find_config_file
19
+ unless path
20
+ Kernel.warn("No #{CONFIG_FILE} found")
21
+ return
22
+ end
23
+
24
+ puts "Loading definitions from #{path}"
25
+
26
+ File.readlines(path).each_with_index do |line, index|
27
+ line_number = index + 1
28
+ process_line(line, line_number, binding)
29
+ end
30
+
31
+ log_summary
32
+ end
33
+
34
+ private
35
+
36
+ def find_config_file
37
+ project_config = File.join(Dir.pwd, CONFIG_FILE)
38
+ return project_config if File.exist?(project_config)
39
+
40
+ home_config = File.join(Dir.home, CONFIG_FILE)
41
+ return home_config if File.exist?(home_config)
42
+
43
+ nil
44
+ end
45
+
46
+ def process_line(line, line_number, binding)
47
+ result = LineValidator.validate(line)
48
+
49
+ if result.valid?
50
+ eval_line(line, binding)
51
+ @loaded_count += 1
52
+ elsif result.error
53
+ Kernel.warn("Line #{line_number}: #{result.error} - #{line.strip}")
54
+ @error_count += 1
55
+ else
56
+ # Blank line or comment - skip silently
57
+ @skipped_count += 1
58
+ end
59
+ rescue StandardError => e
60
+ Kernel.warn("Line #{line_number}: #{e.message}")
61
+ @error_count += 1
62
+ end
63
+
64
+ def eval_line(line, binding)
65
+ binding.eval(line)
66
+ end
67
+
68
+ def log_summary
69
+ puts "Loaded #{@loaded_count} definitions" if @loaded_count.positive?
70
+ Kernel.warn("Skipped #{@error_count} invalid lines") if @error_count.positive?
71
+ end
72
+ end
73
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LazyNames
4
- VERSION = '1.0.0'
4
+ VERSION = '2.0.0'
5
5
  end
data/lib/lazy_names.rb CHANGED
@@ -1,23 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'lazy_names/version'
4
- require 'lazy_names/find_namespace'
5
- require 'lazy_names/config_loader'
6
- require 'lazy_names/config'
7
- require 'lazy_names/config_validator'
8
- require 'lazy_names/definer'
9
- require 'lazy_names/logger'
3
+ require_relative 'lazy_names/version'
4
+ require_relative 'lazy_names/line_validator'
5
+ require_relative 'lazy_names/ruby_loader'
10
6
 
11
7
  module LazyNames
12
- def self.load_definitions!(top_level_binding = TOPLEVEL_BINDING) # rubocop:disable Metrics/AbcSize
13
- basic_config = LazyNames::ConfigLoader
14
- .(namespace: LazyNames::FindNamespace.())
15
- config = LazyNames::Config.new(basic_config.definitions, basic_config.path)
16
- config.validate!
17
- LazyNames::Definer.(config, top_level_binding)
18
-
19
- LazyNames::Logger.warn_undefined(config.errors.undefined, config.path)
20
- LazyNames::Logger.warn_duplicate_definition(config.errors.already_defined, config.path)
21
- LazyNames::Logger.warn_empty_definitions(config.constants.to_a.empty?, config.path)
8
+ def self.load_definitions!(top_level_binding = TOPLEVEL_BINDING)
9
+ RubyLoader.load!(top_level_binding)
22
10
  end
23
11
  end
metadata CHANGED
@@ -1,18 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lazy_names
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - zhisme
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-02-21 00:00:00.000000000 Z
11
+ date: 2026-01-12 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
- lazy_names is ruby programmer friend. You can save your time not typing long
15
- error-phone constants/classes but defining short and nice versions of them.
14
+ lazy_names is ruby programmer friend. Define short aliases for long constant names using plain Ruby.
15
+ Save your time not typing long constants/classes by defining short and intuitive versions of them.
16
16
  email:
17
17
  - evdev34@gmail.com
18
18
  executables: []
@@ -24,27 +24,23 @@ files:
24
24
  - ".github/workflows/codeql.yml"
25
25
  - ".github/workflows/rake.yml"
26
26
  - ".gitignore"
27
- - ".lazy_names.tt.project.yml"
28
- - ".lazy_names.tt.yml"
27
+ - ".lazy_names.tt.rb"
29
28
  - ".rspec"
30
29
  - ".rubocop.yml"
31
30
  - ".ruby-version"
32
- - ".travis.yml"
33
31
  - Gemfile
34
32
  - Gemfile.lock
35
33
  - LICENSE.txt
34
+ - MIGRATION_FROM_V1.md
36
35
  - README.md
37
36
  - Rakefile
38
37
  - bin/console
38
+ - bin/convert_to_v2
39
39
  - bin/setup
40
40
  - lazy_names.gemspec
41
41
  - lib/lazy_names.rb
42
- - lib/lazy_names/config.rb
43
- - lib/lazy_names/config_loader.rb
44
- - lib/lazy_names/config_validator.rb
45
- - lib/lazy_names/definer.rb
46
- - lib/lazy_names/find_namespace.rb
47
- - lib/lazy_names/logger.rb
42
+ - lib/lazy_names/line_validator.rb
43
+ - lib/lazy_names/ruby_loader.rb
48
44
  - lib/lazy_names/version.rb
49
45
  homepage: https://github.com/zhisme/lazy_names
50
46
  licenses:
@@ -69,5 +65,5 @@ requirements: []
69
65
  rubygems_version: 3.3.26
70
66
  signing_key:
71
67
  specification_version: 4
72
- summary: Define short constants to frequently used classes/constants
68
+ summary: Define short aliases for long constant names using plain Ruby
73
69
  test_files: []
@@ -1,3 +0,0 @@
1
- ---
2
- definitions:
3
- 'Models::Users::CreditCard': 'MUCC'
data/.lazy_names.tt.yml DELETED
@@ -1,4 +0,0 @@
1
- ---
2
- my_awesome_project:
3
- definitions:
4
- 'Models::Users::CreditCard': 'MUCC'
data/.travis.yml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- sudo: false
3
- language: ruby
4
- cache: bundler
5
- rvm:
6
- - 2.3.3
7
- before_install: gem install bundler -v 1.16.3
@@ -1,42 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module LazyNames
4
- class Config
5
- extend Forwardable
6
-
7
- attr_reader :path, :validator
8
-
9
- def_delegator :@validator, :errors
10
-
11
- def initialize(definitions, path)
12
- @definitions = definitions
13
- @path = path
14
- @validator = ConfigValidator.new(definitions.values, definitions.keys)
15
- end
16
-
17
- def constants
18
- definitions.keys
19
- end
20
-
21
- def lazy_names
22
- definitions.values
23
- end
24
-
25
- def lazy_name(name)
26
- definitions[name]
27
- end
28
-
29
- def validate!
30
- validator.()
31
- remove_invalid_definitions!
32
- end
33
-
34
- private
35
-
36
- def remove_invalid_definitions!
37
- errors.undefined.each { |name| definitions.delete(name) }
38
- end
39
-
40
- attr_reader :definitions
41
- end
42
- end
@@ -1,91 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'yaml'
4
-
5
- module LazyNames
6
- class ConfigLoader
7
- class NoConfig < StandardError; end
8
- class YAMLConfigInvalid < StandardError; end
9
- class ConfigNotResolved < StandardError; end
10
- class NamespaceNotFound < StandardError; end
11
- class NoDefinitions < StandardError; end
12
-
13
- class << self
14
- BasicConfig = Struct.new(:path, :definitions)
15
- HOME_PATH = '~/.lazy_names.yml'
16
-
17
- def call(namespace:, path: nil)
18
- return read_from_path(namespace, path) if path
19
-
20
- config = read_from_project if config_in_project_path?
21
- config ||= read_from_home_dir(namespace)
22
-
23
- config
24
- end
25
-
26
- private
27
-
28
- def read_from_path(namespace, path)
29
- definitions = find_definitions(path, namespace)
30
-
31
- BasicConfig.new(path, definitions)
32
- rescue Errno::ENOENT, Errno::ENOTDIR
33
- raise NoConfig, "No config found by given path: #{path}"
34
- end
35
-
36
- def read_from_home_dir(namespace)
37
- definitions = find_definitions(home_path, namespace)
38
-
39
- BasicConfig.new(home_path, definitions)
40
- rescue Errno::ENOENT
41
- raise NoConfig, 'No config found in your home directory. ' \
42
- 'Create ~/.lazy_names.yml'
43
- end
44
-
45
- def read_from_project
46
- definitions = find_project_definitions
47
-
48
- BasicConfig.new(project_path, definitions)
49
- end
50
-
51
- def find_project_definitions
52
- read_config(project_path)['definitions'].to_hash
53
- rescue NoMethodError
54
- raise NoDefinitions, "No definitions found in #{project_path}. " \
55
- 'See config example .lazy_names.tt.project.yml'
56
- end
57
-
58
- def find_definitions(path, namespace)
59
- find_namespace_contents(path, namespace)['definitions'].to_hash
60
- rescue NoMethodError
61
- raise NoDefinitions, "No definitions found in #{path}. " \
62
- 'See config example in .lazy_names.tt.yml'
63
- end
64
-
65
- def find_namespace_contents(path, namespace)
66
- read_config(path)[namespace].to_hash
67
- rescue NoMethodError
68
- raise NamespaceNotFound, "No namespace found in #{path}. " \
69
- 'See config example in .lazy_names.tt.yml and check README'
70
- end
71
-
72
- def config_in_project_path?
73
- File.exist?(project_path)
74
- end
75
-
76
- def read_config(path)
77
- YAML.safe_load(File.read(path))
78
- rescue Psych::SyntaxError => e
79
- raise YAMLConfigInvalid, e
80
- end
81
-
82
- def project_path
83
- File.expand_path(Pathname.new(Dir.pwd).join('.lazy_names.yml'))
84
- end
85
-
86
- def home_path
87
- File.expand_path(HOME_PATH)
88
- end
89
- end
90
- end
91
- end
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module LazyNames
4
- class ConfigValidator
5
- attr_reader :errors
6
-
7
- Errors = Struct.new(:undefined, :already_defined)
8
-
9
- def initialize(lazy_names, constants)
10
- @errors = Errors.new([], [])
11
- @constants = constants
12
- @lazy_names = lazy_names
13
- end
14
-
15
- def call
16
- validate_constants!
17
- validate_lazy_names!
18
-
19
- self
20
- end
21
-
22
- private
23
-
24
- attr_reader :lazy_names, :constants
25
-
26
- def validate_constants!
27
- constants.each do |c|
28
- resolve_const_in_project(c)
29
- rescue NameError
30
- self.errors.undefined << c
31
- end
32
- end
33
-
34
- def validate_lazy_names!
35
- a = lazy_names.uniq
36
- b = lazy_names
37
-
38
- diff = difference(b, a)
39
-
40
- return unless diff
41
-
42
- diff.each { |name| self.errors.already_defined << name }
43
- end
44
-
45
- def resolve_const_in_project(const)
46
- Module.const_get(const)
47
- end
48
-
49
- def difference(arr, other)
50
- copy = arr.dup
51
- other.each do |e|
52
- i = copy.rindex(e)
53
- copy.delete_at(i) if i
54
- end
55
-
56
- copy
57
- end
58
- end
59
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module LazyNames
4
- class Definer
5
- class << self
6
- def call(config, top_level_binding)
7
- config.constants.each do |origin|
8
- eval <<-RUBY, top_level_binding, __FILE__, __LINE__ + 1 # rubocop:disable Security/Eval
9
- #{config.lazy_name(origin)} = #{origin} # LN_MC = LazyNames::MyClass. See spec/lazy_names/definer_spec.rb
10
- RUBY
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module LazyNames
4
- class FindNamespace
5
- class << self
6
- ##
7
- # Find project namespace by folder name
8
- #
9
- def call(path = Dir.pwd)
10
- path.split('/').last
11
- end
12
- end
13
- end
14
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module LazyNames
4
- class Logger
5
- class << self
6
- def warn_undefined(errors, config_path)
7
- return if errors.empty?
8
-
9
- message = <<~MSG
10
- Error loading lazy_names gem.
11
- Found #{errors.size} undefined constants.
12
- Please check spelling for #{errors.join(', ')}
13
- #{config_path}
14
- \n
15
- MSG
16
-
17
- warn(message)
18
- end
19
-
20
- def warn_duplicate_definition(errors, config_path)
21
- return if errors.empty?
22
-
23
- message = <<~MSG
24
- Error loading lazy_names gem.
25
- Found #{errors.size} already defined constants.
26
- Using same lazy names for different constants may lead to unexpected results
27
- Avoid duplications in your config file.
28
- #{config_path}
29
- \n
30
- MSG
31
-
32
- warn(message)
33
- end
34
-
35
- def warn_empty_definitions(errors, config_path)
36
- return unless errors
37
-
38
- message = <<~MSG
39
- Error loading lazy_names gem.
40
- Seems like you misspelled namespace in config.
41
- #{config_path}
42
- Please ensure word definitions exists in config
43
- or check .lazy_names.tt.yml for consistency.
44
- MSG
45
-
46
- warn(message)
47
- end
48
- end
49
- end
50
- end