solargraph-rails 1.2.4 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2c75700c14be9b0c73c8f6ec22b567dccc1acf54bc085fe7b592b946ed8fc1fa
4
- data.tar.gz: 6e785a2772256e6b4276e55d699715bad92afe52e659ae523bd289fdbe62a0bc
3
+ metadata.gz: 7b24e92621f34f70e86ce1e93841489deac1c977cc12f80bcb5d097fd0ba2e7c
4
+ data.tar.gz: 8d0299494e027dd55fa9270e4aa7212c00b768c5952cf223f2b998bdb224de20
5
5
  SHA512:
6
- metadata.gz: 6d17000653dde7d3e5d7059805ce73a9cdeb65103775b7da1c6366862d8eb6178c4f3df1451deb0eb326890c12a000128f9dc0204f8559fedc215a25643f48fc
7
- data.tar.gz: e2999b7c83c2c45ab6955f3aff072bcd43b1b8a32b655076d29066d1f65a6d7087705a12f26d63fa2f6471311f90d97a25fa02f1be51f100cb09784c144ab2cd
6
+ metadata.gz: b63b981c50f993725af679aa99ed89572656005c5114e408c90d33b37fbdcc450be4ddd0e07cd2876babf41f0b4efc84e0b866a121ca94a5e79b1592e8383552
7
+ data.tar.gz: 0a1ed573aa727c4aa0a96488c23e27ce34f813840ec44f0c58d6d214c6d49df0d53e9158a648bb2101fe0fff901097979e045906f0b60baaf329b123bbb75f7b
@@ -42,7 +42,7 @@ jobs:
42
42
  - uses: ruby/setup-ruby@v1
43
43
  with:
44
44
  ruby-version: 3.4
45
- bundler: latest
45
+ bundler: Gemfile.lock
46
46
  bundler-cache: true
47
47
  cache-version: ${{ matrix.solargraph-version }}-${{ matrix.versions.rails-major }}.${{ matrix.versions.rails-minor }}-2025-06-06
48
48
  env:
@@ -0,0 +1,101 @@
1
+ # To debug locally:
2
+ # npm install -g act
3
+ # act pull_request
4
+ #
5
+
6
+ name: New Rails project
7
+
8
+ on:
9
+ workflow_dispatch: {}
10
+ pull_request:
11
+ branches: [main]
12
+ push:
13
+ branches:
14
+ - 'main'
15
+ tags:
16
+ - 'v*'
17
+
18
+ jobs:
19
+ typecheck_strong:
20
+ name: strong typecheck
21
+ runs-on: ubuntu-latest
22
+ strategy:
23
+ matrix:
24
+ versions:
25
+ # ruby 3.2 is minimum Ruby supported by Rails 8.0
26
+ - ruby: "3.2"
27
+ rails-major: "8"
28
+ rails-minor: "0"
29
+ - ruby: "3.2"
30
+ rails-major: "7"
31
+ rails-minor: "0"
32
+ - ruby: "3.2"
33
+ rails-major: "7"
34
+ rails-minor: "1"
35
+ fail-fast: false
36
+ steps:
37
+ - uses: actions/checkout@v2
38
+ - uses: ruby/setup-ruby@v1
39
+ with:
40
+ ruby-version: ${{ matrix.versions.ruby }}
41
+ bundler: Gemfile.lock
42
+ bundler-cache: true
43
+ cache-version: ${{ matrix.solargraph-version }}-${{ matrix.versions.rails-major }}.${{ matrix.versions.rails-minor }}-2025-09-09
44
+ env:
45
+ MATRIX_RAILS_MAJOR_VERSION: ${{ matrix.versions.rails-major }}
46
+ MATRIX_RAILS_VERSION: ${{ matrix.versions.rails-major }}.${{ matrix.versions.rails-minor }}
47
+ - uses: awalsh128/cache-apt-pkgs-action@latest
48
+ with:
49
+ packages: yq
50
+ version: 1.0
51
+ - name: Restore cache of gem annotations
52
+ id: dot-cache-restore
53
+ uses: actions/cache/restore@v4
54
+ with:
55
+ key: |
56
+ 2025-09-09-${{ runner.os }}-dot-cache-${{ matrix.solargraph-version }}-${{ matrix.versions.rails-major }}--${{ matrix.versions.rails-minor }}-${{ hashFiles('spec/**/Gemfile.lock') }}-${{ hashFiles('Gemfile.lock') }}
57
+ restore-keys: |
58
+ 2025-09-09-${{ runner.os }}-dot-cache-${{ matrix.solargraph-version }}-${{ matrix.versions.rails-major }}-${{ matrix.versions.rails-minor }}-${{ hashFiles('spec/**/Gemfile.lock') }}-
59
+ 2025-09-09-${{ runner.os }}-dot-cache-${{ matrix.solargraph-version }}-${{ matrix.versions.rails-major }}-${{ matrix.versions.rails-minor }}-
60
+ 2025-09-09-${{ runner.os }}-dot-cache-${{ matrix.solargraph-version }}-${{ matrix.versions.rails-major }}-
61
+ 2025-09-09-${{ runner.os }}-dot-cache-${{ matrix.solargraph-version }}-
62
+ path: |
63
+ /home/runner/.cache/solargraph
64
+
65
+ - name: Typecheck default 'rails new' code
66
+ run: |
67
+ set -ex
68
+ bundle update solargraph
69
+ gem install rails -v '~> ${{ matrix.versions.rails-major }}.${{ matrix.versions.rails-minor }}.0'
70
+ gem uninstall -I concurrent-ruby
71
+ # https://stackoverflow.com/questions/79360526/uninitialized-constant-activesupportloggerthreadsafelevellogger-nameerror
72
+ gem install concurrent-ruby -v 1.3.4
73
+ pwd
74
+ cd ..
75
+ rails new test-project
76
+ cd test-project
77
+ echo 'gem "solargraph-rails", path: "../solargraph-rails"' >> Gemfile
78
+ echo 'gem "solargraph", github: "castwide/solargraph", branch: "master"' >> Gemfile
79
+ # https://stackoverflow.com/questions/79360526/uninitialized-constant-activesupportloggerthreadsafelevellogger-nameerror
80
+ echo "gem 'concurrent-ruby', '1.3.4'" >> Gemfile
81
+ bundle install
82
+ bundle info solargraph
83
+ bundle info solargraph-rails
84
+ bin/rails --version
85
+ bundle exec rbs collection init
86
+ bundle exec rbs collection install
87
+ bundle exec solargraph config
88
+ yq -yi '.plugins += ["solargraph-rails"]' .solargraph.yml
89
+ bundle exec solargraph typecheck --level strong
90
+ env:
91
+ MATRIX_RAILS_MAJOR_VERSION: ${{ matrix.versions.rails-major }}
92
+ MATRIX_RAILS_VERSION: ${{ matrix.versions.rails-major }}.${{ matrix.versions.rails-minor }}
93
+ - name: Cache gem annotations
94
+ id: dot-cache-save
95
+ if: always() && steps.dot-cache-restore.outputs.cache-hit != 'true'
96
+ uses: actions/cache/save@v4
97
+ with:
98
+ key: |
99
+ 2025-09-09-${{ runner.os }}-dot-cache-${{ matrix.solargraph-version }}-${{ matrix.versions.rails-major }}--${{ matrix.versions.rails-minor }}-${{ hashFiles('spec/**/Gemfile.lock') }}-${{ hashFiles('Gemfile.lock') }}
100
+ path: |
101
+ /home/runner/.cache/solargraph
@@ -47,6 +47,7 @@ jobs:
47
47
  - "0.56.1"
48
48
  - "0.56.2"
49
49
  - "0.57.0"
50
+ # - "0.58.0"
50
51
  - "branch-castwide-master"
51
52
  include:
52
53
  - versions:
@@ -62,7 +63,7 @@ jobs:
62
63
  - uses: ruby/setup-ruby@v1
63
64
  with:
64
65
  ruby-version: ${{ matrix.versions.ruby }}
65
- bundler: latest
66
+ bundler: Gemfile.lock
66
67
  bundler-cache: true
67
68
  cache-version: ${{ matrix.solargraph-version }}-${{ matrix.versions.rails-major }}.${{ matrix.versions.rails-minor }}-2025-09-09
68
69
  env:
@@ -25,7 +25,7 @@ jobs:
25
25
  - uses: ruby/setup-ruby@v1
26
26
  with:
27
27
  ruby-version: 3.4
28
- bundler: latest
28
+ bundler: Gemfile.lock
29
29
  bundler-cache: true
30
30
  cache-version: ${{ matrix.versions.rails-major }}.${{ matrix.versions.rails-minor }}-2025-06-06
31
31
  env:
data/CHANGELOG.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  ## Changes
4
4
 
5
+ ### v1.3
6
+
7
+ Features/fixes:
8
+ - Add support for Puma DSL
9
+ - Add support for importmap.rb DSL
10
+ - Type annotations for schema.rb
11
+ - Remove Solargraph upper limit in gemspec
12
+
13
+ Internal improvements:
14
+ - Create a 'rails new' GitHub Actions workflow
15
+
5
16
  ### v1.2.4
6
17
 
7
18
  Features / fixes:
data/DEVELOPMENT.md CHANGED
@@ -73,7 +73,7 @@ Move .yml files into place, then make sure to review the script and uncomment re
73
73
  ## Preparing a release (maintainers)
74
74
 
75
75
  1. Look up [most recent release](https://rubygems.org/gems/solargraph-rails)
76
- 2. Open up [commit list](https://github.com/iftheshoefritz/solargraph-rails/compare/v1.2.3...main)
76
+ 2. Open up [commit list](https://github.com/iftheshoefritz/solargraph-rails/compare/v1.2.4...main)
77
77
  3. Update [CHANGELOG.md](./CHANGELOG.md)
78
78
  4. Flip to 'files changed view' and refine updates
79
79
  5. Bump [version](./lib/solargraph/rails/version.rb) appropriately
@@ -16,6 +16,129 @@ class ActiveRecord::ConnectionAdapters::SchemaStatements
16
16
  def change_table(table_name, **options); end
17
17
  end
18
18
 
19
+ class ActiveRecord::ConnectionAdapters::ColumnMethods
20
+ # included do
21
+ # define_column_methods :bigint, :binary, :boolean, :date, :datetime, :decimal,
22
+ # :float, :integer, :json, :string, :text, :time, :timestamp, :virtual
23
+ # alias :blob :binary
24
+ # alias :numeric :decimal
25
+ # end
26
+
27
+ # def define_column_methods(*column_types) # :nodoc:
28
+ # column_types.each do |column_type|
29
+ # module_eval <<-RUBY, __FILE__, __LINE__ + 1
30
+ # def #{column_type}(*names, **options)
31
+ # raise ArgumentError, "Missing column name(s) for #{column_type}" if names.empty?
32
+ # names.each { |name| column(name, :#{column_type}, **options) }
33
+ # end
34
+ # RUBY
35
+ # end
36
+
37
+ # decimal
38
+ #
39
+ # @param names [Array<Symbol, String>]
40
+ # @param precision [Integer, nil]
41
+ # @param scale [Integer, nil]
42
+ # @param options [Hash{Symbol => undefined}]
43
+ # @return [void]
44
+ def decimal(*names, precision: nil, scale: nil, **options); end
45
+ # bigint
46
+ #
47
+ # @param names [Array<Symbol, String>]
48
+ # @param options [Hash{Symbol => undefined}]
49
+ # @return [void]
50
+ def bigint(*names, **options); end
51
+ # virtual
52
+ #
53
+ # @param names [Array<Symbol, String>]
54
+ # @param type [Symbol, String]
55
+ # @param as [String]
56
+ # @param options [Hash{Symbol => undefined}]
57
+ # @return [void]
58
+ def virtual(*names, type, as:, **options); end
59
+ # json
60
+ #
61
+ # @param names [Array<Symbol, String>]
62
+ # @param options [Hash{Symbol => undefined}]
63
+ # @return [void]
64
+ def json(*names, **options); end
65
+ # jsonb
66
+ #
67
+ # @param names [Array<Symbol, String>]
68
+ # @param options [Hash{Symbol => undefined}]
69
+ # @return [void]
70
+ def jsonb(*names, **options); end
71
+ # boolean
72
+ #
73
+ # @param names [Array<Symbol, String>]
74
+ # @param options [Hash{Symbol => undefined}]
75
+ # @param names [Array<Symbol, String>]
76
+ # @return [void]
77
+ def boolean(*names, **options); end
78
+ # string
79
+ #
80
+ # @param names [Array<Symbol, String>]
81
+ # @param limit [Integer, nil]
82
+ # @param options [Hash{Symbol => undefined}]
83
+ # @return [void]
84
+ def string(*names, limit: nil, **options); end
85
+ # text
86
+ #
87
+ # @param names [Array<Symbol, String>]
88
+ # @param limit [Integer, nil]
89
+ # @param options [Hash{Symbol => undefined}]
90
+ # @return [void]
91
+ def text(*names, limit: nil, **options); end
92
+ # integer
93
+ #
94
+ # @param names [Array<Symbol, String>]
95
+ # @param limit [Integer, nil]
96
+ # @param options [Hash{Symbol => undefined}]
97
+ # @return [void]
98
+ def integer(*names, limit: nil, **options); end
99
+ # float
100
+ #
101
+ # @param names [Array<Symbol, String>]
102
+ # @param limit [Integer, nil]
103
+ # @param options [Hash{Symbol => undefined}]
104
+ # @return [void]
105
+ def float(*names, limit: nil, **options); end
106
+ # binary
107
+ #
108
+ # @param names [Array<Symbol, String>]
109
+ # @param limit [Integer, nil]
110
+ # @param options [Hash{Symbol => undefined}]
111
+ # @return [void]
112
+ def binary(*names, limit: nil, **options); end
113
+ # date
114
+ #
115
+ # @param names [Array<Symbol, String>]
116
+ # @param options [Hash{Symbol => undefined}]
117
+ # @return [void]
118
+ def date(*names, **options); end
119
+ # datetime
120
+ #
121
+ # @param names [Array<Symbol, String>]
122
+ # @param precision [Integer, nil]
123
+ # @param options [Hash{Symbol => undefined}]
124
+ # @return [void]
125
+ def datetime(*names, precision: nil, **options); end
126
+ # time
127
+ #
128
+ # @param names [Array<Symbol, String>]
129
+ # @param precision [Integer, nil]
130
+ # @param options [Hash{Symbol => undefined}]
131
+ # @return [void]
132
+ def time(*names, precision: nil, **options); end
133
+ # timestamp
134
+ #
135
+ # @param names [Array<Symbol, String>]
136
+ # @param precision [Integer, nil]
137
+ # @param options [Hash{Symbol => undefined}]
138
+ # @return [void]
139
+ def timestamp(*names, precision: nil, **options); end
140
+ end
141
+
19
142
  module ActiveRecord::Core
20
143
  # @param methods [Symbol]
21
144
  # @return [ActiveSupport::HashWithIndifferentAccess<Symbol>]
@@ -35,6 +158,18 @@ class ActiveRecord::Relation
35
158
  include ActiveRecord::RelationMethods
36
159
  end
37
160
 
161
+ module ActiveRecord
162
+ class Schema
163
+ # @param version [Numeric]
164
+ #
165
+ # @return [Class<ActiveRecord::Schema>]
166
+ def self.[](version); end
167
+
168
+ # @yieldreceiver [ActiveRecord::ConnectionAdapters::SchemaStatements]
169
+ def self.define(info = {}, &block); end
170
+ end
171
+ end
172
+
38
173
  class ActiveRecord::Base
39
174
  extend Enumerable
40
175
  extend ActiveRecord::QueryMethods
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Rails
5
+ class Importmap
6
+ EMPTY_ENVIRON = Environ.new
7
+
8
+ # @return [Solargraph::Rails::Importmap]
9
+ def self.instance
10
+ @instance ||= new
11
+ end
12
+
13
+ # @param environ [Solargraph::Environ]
14
+ # @param basename [String]
15
+ #
16
+ # @return [void]
17
+ def add_dsl(environ, basename)
18
+ return unless basename == 'importmap.rb'
19
+
20
+ environ.requires.push('importmap-rails')
21
+ environ.domains.push('Importmap::Map')
22
+
23
+ Solargraph.logger.debug(
24
+ "[Rails][Importmap] added DSL to environ: #{environ.inspect}"
25
+ )
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Rails
5
+ class Puma
6
+ EMPTY_ENVIRON = Environ.new
7
+
8
+ # @return [Solargraph::Rails::Puma]
9
+ def self.instance
10
+ @instance ||= new
11
+ end
12
+
13
+ # @param environ [Solargraph::Environ]
14
+ # @param basename [String]
15
+ #
16
+ # @return [void]
17
+ def add_dsl(environ, basename)
18
+ return unless basename == 'puma.rb'
19
+
20
+ environ.requires.push('puma')
21
+ environ.domains.push('Puma::DSL')
22
+
23
+ Solargraph.logger.debug(
24
+ "[Rails][Puma] added DSL to environ: #{environ.inspect}"
25
+ )
26
+ end
27
+ end
28
+ end
29
+ end
@@ -1,5 +1,5 @@
1
1
  module Solargraph
2
2
  module Rails
3
- VERSION = '1.2.4'
3
+ VERSION = '1.3'
4
4
  end
5
5
  end
@@ -13,6 +13,8 @@ require_relative 'solargraph/rails/walker'
13
13
  require_relative 'solargraph/rails/rails_api'
14
14
  require_relative 'solargraph/rails/delegate'
15
15
  require_relative 'solargraph/rails/storage'
16
+ require_relative 'solargraph/rails/puma'
17
+ require_relative 'solargraph/rails/importmap'
16
18
  require_relative 'solargraph/rails/debug'
17
19
  require_relative 'solargraph/rails/version'
18
20
 
@@ -23,6 +25,9 @@ module Solargraph
23
25
  end
24
26
 
25
27
  class Convention < Solargraph::Convention::Base
28
+ # @param yard_map [Solargraph::DocMap]
29
+ #
30
+ # @return [Solargraph::Environ]
26
31
  def global(yard_map)
27
32
  Solargraph::Environ.new(
28
33
  pins: Solargraph::Rails::RailsApi.instance.global(yard_map)
@@ -34,6 +39,9 @@ module Solargraph
34
39
  EMPTY_ENVIRON
35
40
  end
36
41
 
42
+ # @param source_map [Solargraph::SourceMap]
43
+ #
44
+ # @return [Solargraph::Environ]
37
45
  def local(source_map)
38
46
  pins = []
39
47
  ds =
@@ -42,7 +50,13 @@ module Solargraph
42
50
  end
43
51
  ns = ds.first
44
52
 
45
- return EMPTY_ENVIRON unless ns
53
+ basename = File.basename(source_map.filename)
54
+
55
+ environ = Solargraph::Environ.new
56
+ Puma.instance.add_dsl(environ, basename)
57
+ Importmap.instance.add_dsl(environ, basename)
58
+
59
+ return environ unless ns
46
60
 
47
61
  pins += run_feature { Schema.instance.process(source_map, ns) }
48
62
  pins += run_feature { Annotate.instance.process(source_map, ns) }
@@ -53,11 +67,16 @@ module Solargraph
53
67
  pins += run_feature { Delegate.instance.process(source_map, ns) } if Delegate.supported?
54
68
  pins += run_feature { RailsApi.instance.local(source_map, ns) }
55
69
 
56
- Solargraph::Environ.new(pins: pins)
70
+ environ = Solargraph::Environ.new(pins: pins)
71
+ Puma.instance.add_dsl(environ, basename)
72
+ environ
57
73
  end
58
74
 
59
75
  private
60
76
 
77
+ # @yieldreturn [Array<Solargraph::Pin::Base>]
78
+ #
79
+ # @return [Array<Solargraph::Pin::Base>]
61
80
  def run_feature(&block)
62
81
  yield
63
82
  rescue => error
@@ -6,14 +6,10 @@ require 'solargraph/rails/version'
6
6
  solargraph_force_ci_version = (ENV['CI'] && ENV['MATRIX_SOLARGRAPH_VERSION'])
7
7
  solargraph_version =
8
8
  if solargraph_force_ci_version && !solargraph_force_ci_version.start_with?('branch-')
9
- [solargraph_force_ci_version]
9
+ solargraph_force_ci_version
10
10
  else
11
- [
12
- # below this isn't tested in CI
13
- '>= 0.48.0',
14
- # above this hasn't been tested
15
- '<= 0.57'
16
- ]
11
+ # below this isn't tested in CI
12
+ '>= 0.48.0'
17
13
  end
18
14
 
19
15
  Gem::Specification.new do |spec|
@@ -37,7 +33,7 @@ Gem::Specification.new do |spec|
37
33
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
38
34
  spec.require_paths = ['lib']
39
35
 
40
- spec.add_development_dependency 'bundler', '~> 2.3'
36
+ spec.add_development_dependency 'bundler', '>= 2.2.33'
41
37
  spec.add_development_dependency 'rake', '~> 12.3.3'
42
38
  spec.add_development_dependency 'rspec', '~> 3.0'
43
39
  spec.add_development_dependency 'rubocop', '~> 1.76'
metadata CHANGED
@@ -1,28 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solargraph-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.4
4
+ version: '1.3'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fritz Meissner
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-09-16 00:00:00.000000000 Z
10
+ date: 2026-01-01 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: bundler
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
- - - "~>"
16
+ - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: '2.3'
18
+ version: 2.2.33
19
19
  type: :development
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
- - - "~>"
23
+ - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: '2.3'
25
+ version: 2.2.33
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: rake
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -100,9 +100,6 @@ dependencies:
100
100
  - - ">="
101
101
  - !ruby/object:Gem::Version
102
102
  version: 0.48.0
103
- - - "<="
104
- - !ruby/object:Gem::Version
105
- version: '0.57'
106
103
  type: :runtime
107
104
  prerelease: false
108
105
  version_requirements: !ruby/object:Gem::Requirement
@@ -110,9 +107,6 @@ dependencies:
110
107
  - - ">="
111
108
  - !ruby/object:Gem::Version
112
109
  version: 0.48.0
113
- - - "<="
114
- - !ruby/object:Gem::Version
115
- version: '0.57'
116
110
  - !ruby/object:Gem::Dependency
117
111
  name: activesupport
118
112
  requirement: !ruby/object:Gem::Requirement
@@ -137,6 +131,7 @@ extra_rdoc_files: []
137
131
  files:
138
132
  - ".github/ISSUE_TEMPLATE/bug_report.md"
139
133
  - ".github/workflows/linter.yml"
134
+ - ".github/workflows/rails_new.yml"
140
135
  - ".github/workflows/test.yml"
141
136
  - ".github/workflows/typecheck.yml"
142
137
  - ".gitignore"
@@ -184,7 +179,9 @@ files:
184
179
  - lib/solargraph/rails/debug.rb
185
180
  - lib/solargraph/rails/delegate.rb
186
181
  - lib/solargraph/rails/devise.rb
182
+ - lib/solargraph/rails/importmap.rb
187
183
  - lib/solargraph/rails/model.rb
184
+ - lib/solargraph/rails/puma.rb
188
185
  - lib/solargraph/rails/rails_api.rb
189
186
  - lib/solargraph/rails/schema.rb
190
187
  - lib/solargraph/rails/storage.rb