Skip to content

Commit a5dc611

Browse files
transclaude
andcommitted
Release prep: version 3.2.0
- Replace Indexer-based gemspec with standard Gem::Specification - Set version to 3.2.0 in gemspec and version.rb - Simplify version.rb (remove old YAML index dependency) - Set release date in HISTORY.md - Require Ruby >= 3.1 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent dff07ae commit a5dc611

File tree

3 files changed

+34
-322
lines changed

3 files changed

+34
-322
lines changed

HISTORY.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Facets Release History
22

3-
## 3.2.0 / (Unreleased)
3+
## 3.2.0 / 2026-04-01
44

55
Modernization release targeting Ruby 3.1+. Cleans up long-standing
66
compatibility issues and incorporates community contributions.

facets.gemspec

Lines changed: 32 additions & 304 deletions
Original file line numberDiff line numberDiff line change
@@ -1,305 +1,33 @@
1-
# encoding: utf-8
2-
3-
require 'yaml'
4-
require 'pathname'
5-
6-
module Indexer
7-
8-
# Convert index data into a gemspec.
9-
#
10-
# Notes:
11-
# * Assumes all executables are in bin/.
12-
# * Does not yet handle default_executable setting.
13-
# * Does not yet handle platform setting.
14-
# * Does not yet handle required_ruby_version.
15-
# * Support for rdoc entries is weak.
16-
#
17-
class GemspecExporter
18-
19-
# File globs to include in package --unless a manifest file exists.
20-
FILES = ".index .yardopts alt bin data demo ext features lib man spec test try* [A-Z]*.*" unless defined?(FILES)
21-
22-
# File globs to omit from FILES.
23-
OMIT = "Config.rb" unless defined?(OMIT)
24-
25-
# Standard file patterns.
26-
PATTERNS = {
27-
:root => '{.index,Gemfile}',
28-
:bin => 'bin/*',
29-
:lib => 'lib/{**/}*', #.rb',
30-
:ext => 'ext/{**/}extconf.rb',
31-
:doc => '*.{txt,rdoc,md,markdown,tt,textile}',
32-
:test => '{test,spec}/{**/}*.rb'
33-
} unless defined?(PATTERNS)
34-
35-
# For which revision of indexer spec is this converter intended?
36-
REVISION = 2013 unless defined?(REVISION)
37-
38-
#
39-
def self.gemspec
40-
new.to_gemspec
41-
end
42-
43-
#
44-
attr :metadata
45-
46-
#
47-
def initialize(metadata=nil)
48-
@root_check = false
49-
50-
if metadata
51-
root_dir = metadata.delete(:root)
52-
if root_dir
53-
@root = root_dir
54-
@root_check = true
55-
end
56-
metadata = nil if metadata.empty?
57-
end
58-
59-
@metadata = metadata || YAML.load_file(root + '.index')
60-
61-
if @metadata['revision'].to_i != REVISION
62-
warn "This gemspec exporter was not designed for this revision of index metadata."
63-
end
64-
end
65-
66-
#
67-
def has_root?
68-
root ? true : false
69-
end
70-
71-
#
72-
def root
73-
return @root if @root || @root_check
74-
@root_check = true
75-
@root = find_root
76-
end
77-
78-
#
79-
def manifest
80-
return nil unless root
81-
@manifest ||= Dir.glob(root + 'manifest{,.txt}', File::FNM_CASEFOLD).first
82-
end
83-
84-
#
85-
def scm
86-
return nil unless root
87-
@scm ||= %w{git hg}.find{ |m| (root + ".#{m}").directory? }.to_sym
88-
end
89-
90-
#
91-
def files
92-
return [] unless root
93-
@files ||= \
94-
if manifest
95-
File.readlines(manifest).
96-
map{ |line| line.strip }.
97-
reject{ |line| line.empty? || line[0,1] == '#' }
98-
else
99-
list = []
100-
Dir.chdir(root) do
101-
FILES.split(/\s+/).each do |pattern|
102-
list.concat(glob(pattern))
103-
end
104-
OMIT.split(/\s+/).each do |pattern|
105-
list = list - glob(pattern)
106-
end
107-
end
108-
list
109-
end.select{ |path| File.file?(path) }.uniq
110-
end
111-
112-
#
113-
def glob_files(pattern)
114-
return [] unless root
115-
Dir.chdir(root) do
116-
Dir.glob(pattern).select do |path|
117-
File.file?(path) && files.include?(path)
118-
end
119-
end
120-
end
121-
122-
def patterns
123-
PATTERNS
124-
end
125-
126-
def executables
127-
@executables ||= \
128-
glob_files(patterns[:bin]).map do |path|
129-
File.basename(path)
130-
end
131-
end
132-
133-
def extensions
134-
@extensions ||= \
135-
glob_files(patterns[:ext]).map do |path|
136-
File.basename(path)
137-
end
138-
end
139-
140-
def name
141-
metadata['name'] || metadata['title'].downcase.gsub(/\W+/,'_')
142-
end
143-
144-
def homepage
145-
page = (
146-
metadata['resources'].find{ |r| r['type'] =~ /^home/i } ||
147-
metadata['resources'].find{ |r| r['name'] =~ /^home/i } ||
148-
metadata['resources'].find{ |r| r['name'] =~ /^web/i }
149-
)
150-
page ? page['uri'] : false
151-
end
152-
153-
def licenses
154-
metadata['copyrights'].map{ |c| c['license'] }.compact
155-
end
156-
157-
def require_paths
158-
paths = metadata['paths'] || {}
159-
paths['load'] || ['lib']
160-
end
161-
162-
#
163-
# Convert to gemnspec.
164-
#
165-
def to_gemspec
166-
if has_root?
167-
Gem::Specification.new do |gemspec|
168-
to_gemspec_data(gemspec)
169-
to_gemspec_paths(gemspec)
170-
end
171-
else
172-
Gem::Specification.new do |gemspec|
173-
to_gemspec_data(gemspec)
174-
to_gemspec_paths(gemspec)
175-
end
176-
end
177-
end
178-
179-
#
180-
# Convert pure data settings.
181-
#
182-
def to_gemspec_data(gemspec)
183-
gemspec.name = name
184-
gemspec.version = metadata['version']
185-
gemspec.summary = metadata['summary']
186-
gemspec.description = metadata['description']
187-
188-
metadata['authors'].each do |author|
189-
gemspec.authors << author['name']
190-
191-
if author.has_key?('email')
192-
if gemspec.email
193-
gemspec.email << author['email']
194-
else
195-
gemspec.email = [author['email']]
196-
end
197-
end
198-
end
199-
200-
gemspec.licenses = licenses
201-
202-
requirements = metadata['requirements'] || []
203-
requirements.each do |req|
204-
next if req['optional']
205-
next if req['external']
206-
207-
name = req['name']
208-
groups = req['groups'] || []
209-
210-
version = gemify_version(req['version'])
211-
212-
if groups.empty? or groups.include?('runtime')
213-
# populate runtime dependencies
214-
if gemspec.respond_to?(:add_runtime_dependency)
215-
gemspec.add_runtime_dependency(name,*version)
216-
else
217-
gemspec.add_dependency(name,*version)
218-
end
219-
else
220-
# populate development dependencies
221-
if gemspec.respond_to?(:add_development_dependency)
222-
gemspec.add_development_dependency(name,*version)
223-
else
224-
gemspec.add_dependency(name,*version)
225-
end
226-
end
227-
end
228-
229-
# convert external dependencies into gemspec requirements
230-
requirements.each do |req|
231-
next unless req['external']
232-
gemspec.requirements << ("%s-%s" % req.values_at('name', 'version'))
233-
end
234-
235-
gemspec.homepage = homepage
236-
gemspec.require_paths = require_paths
237-
gemspec.post_install_message = metadata['install_message']
238-
end
239-
240-
#
241-
# Set gemspec settings that require a root directory path.
242-
#
243-
def to_gemspec_paths(gemspec)
244-
gemspec.files = files
245-
gemspec.extensions = extensions
246-
gemspec.executables = executables
247-
248-
if Gem::VERSION < '1.7.'
249-
gemspec.default_executable = gemspec.executables.first
250-
end
251-
252-
unless gemspec.files.include?('.document')
253-
gemspec.extra_rdoc_files = glob_files(patterns[:doc])
254-
end
255-
end
256-
257-
#
258-
# Return a copy of this file. This is used to generate a local
259-
# .gemspec file that can automatically read the index file.
260-
#
261-
def self.source_code
262-
File.read(__FILE__)
263-
end
264-
265-
private
266-
267-
def find_root
268-
root_files = patterns[:root]
269-
if Dir.glob(root_files).first
270-
Pathname.new(Dir.pwd)
271-
elsif Dir.glob("../#{root_files}").first
272-
Pathname.new(Dir.pwd).parent
273-
else
274-
#raise "Can't find root of project containing `#{root_files}'."
275-
warn "Can't find root of project containing `#{root_files}'."
276-
nil
277-
end
278-
end
279-
280-
def glob(pattern)
281-
if File.directory?(pattern)
282-
Dir.glob(File.join(pattern, '**', '*'))
283-
else
284-
Dir.glob(pattern)
285-
end
286-
end
287-
288-
def gemify_version(version)
289-
case version
290-
when /^(.*?)\+$/
291-
">= #{$1}"
292-
when /^(.*?)\-$/
293-
"< #{$1}"
294-
when /^(.*?)\~$/
295-
"~> #{$1}"
296-
else
297-
version
298-
end
299-
end
300-
301-
end
302-
1+
Gem::Specification.new do |s|
2+
s.name = 'facets'
3+
s.version = '3.2.0'
4+
s.summary = 'The premier collection of extension methods for Ruby.'
5+
s.description = 'Facets is the premier collection of extension methods for the Ruby ' \
6+
'programming language. Facets extensions are unique by virtue of their ' \
7+
'atomicity. They are stored in individual files allowing for highly ' \
8+
'granular control of requirements. In addition, Facets includes a few ' \
9+
'additional classes and mixins suitable to a wide variety of applications.'
10+
11+
s.authors = ['Thomas Sawyer']
12+
s.email = ['transfire@gmail.com']
13+
s.homepage = 'https://github.com/rubyworks/facets'
14+
s.license = 'BSD-2-Clause'
15+
16+
s.required_ruby_version = '>= 3.1'
17+
18+
s.files = Dir[
19+
'lib/**/*.rb',
20+
'LICENSE.txt',
21+
'README.md',
22+
'HISTORY.md',
23+
'CONTRIBUTING.md'
24+
]
25+
26+
s.require_paths = ['lib/core', 'lib/standard']
27+
28+
s.metadata = {
29+
'homepage_uri' => s.homepage,
30+
'source_code_uri' => 'https://github.com/rubyworks/facets',
31+
'changelog_uri' => 'https://github.com/rubyworks/facets/blob/main/HISTORY.md'
32+
}
30333
end
304-
305-
Indexer::GemspecExporter.gemspec

lib/core/facets/version.rb

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,3 @@
11
module Facets
2-
#
3-
def self.index
4-
@index ||= (
5-
require 'yaml'
6-
YAML.load(File.new(File.dirname(__FILE__) + '/facets.yml'))
7-
)
8-
end
9-
10-
#
11-
def self.const_missing(name)
12-
key = name.to_s.downcase
13-
index[key] || super(name)
14-
end
15-
16-
# deprecate
17-
VERSION = '3.0.0'
2+
VERSION = '3.2.0'
183
end
19-

0 commit comments

Comments
 (0)