-
Notifications
You must be signed in to change notification settings - Fork 52
[Feature #21264] Replace C extension with pure Ruby implementation for Ruby >= 3.3 #155
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 10 commits
bae5812
0cdfd42
802e0c2
d4aa1aa
8909ef5
d276c80
2b938aa
fb37439
ea0355e
a65aca6
7e80db9
a9255c0
aa536c6
1b3b1ef
fd03c6f
997de16
e2698ea
a539110
c211307
e67f196
5bcb504
d80a88b
382bb9a
a6abfc1
7c04350
9e9d45a
e880620
20198e3
d0b25b2
c9b2175
f6a2947
3773d98
6786840
4e11ebb
4a2bf55
9131c63
8795e36
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,30 +1,47 @@ | ||
| require "bundler/gem_tasks" | ||
| require "rake/testtask" | ||
| require "shellwords" | ||
| require "rake/extensiontask" | ||
|
|
||
| extask = Rake::ExtensionTask.new("date") do |ext| | ||
| ext.name = "date_core" | ||
| ext.lib_dir.sub!(%r[(?=/|\z)], "/#{RUBY_VERSION}/#{ext.platform}") | ||
| end | ||
| if RUBY_VERSION >= "3.3" | ||
| # Pure Ruby — no compilation needed | ||
| Rake::TestTask.new(:test) do |t| | ||
| t.libs << "lib" | ||
| t.libs << "test/lib" | ||
| t.ruby_opts << "-rhelper" | ||
| t.test_files = FileList['test/**/test_*.rb'] | ||
| end | ||
|
|
||
| Rake::TestTask.new(:test) do |t| | ||
| t.libs << extask.lib_dir | ||
| t.libs << "test/lib" | ||
| t.ruby_opts << "-rhelper" | ||
| t.test_files = FileList['test/**/test_*.rb'] | ||
| end | ||
| task :compile # no-op | ||
|
|
||
| else | ||
| # C extension for Ruby < 3.3 | ||
| require "shellwords" | ||
| require "rake/extensiontask" | ||
|
|
||
| extask = Rake::ExtensionTask.new("date") do |ext| | ||
| ext.name = "date_core" | ||
| ext.lib_dir.sub!(%r[(?=/|\z)], "/#{RUBY_VERSION}/#{ext.platform}") | ||
| end | ||
|
|
||
| Rake::TestTask.new(:test) do |t| | ||
| t.libs << extask.lib_dir | ||
| t.libs << "test/lib" | ||
| t.ruby_opts << "-rhelper" | ||
| t.test_files = FileList['test/**/test_*.rb'] | ||
| end | ||
|
|
||
| task test: :compile | ||
|
|
||
| task compile: "ext/date/zonetab.h" | ||
| file "ext/date/zonetab.h" => "ext/date/zonetab.list" do |t| | ||
| dir, hdr = File.split(t.name) | ||
| make_program_name = | ||
| ENV['MAKE'] || ENV['make'] || | ||
| RbConfig::CONFIG['configure_args'][/with-make-prog\=\K\w+/] || | ||
| (/mswin/ =~ RUBY_PLATFORM ? 'nmake' : 'make') | ||
| make_program = Shellwords.split(make_program_name) | ||
| sh(*make_program, "-f", "prereq.mk", "top_srcdir=.."+"/.."*dir.count("/"), | ||
| hdr, chdir: dir) | ||
| task compile: "ext/date/zonetab.h" | ||
| file "ext/date/zonetab.h" => "ext/date/zonetab.list" do |t| | ||
| dir, hdr = File.split(t.name) | ||
| make_program_name = | ||
| ENV['MAKE'] || ENV['make'] || | ||
| RbConfig::CONFIG['configure_args'][/with-make-prog\=\K\w+/] || | ||
| (/mswin/ =~ RUBY_PLATFORM ? 'nmake' : 'make') | ||
| make_program = Shellwords.split(make_program_name) | ||
| sh(*make_program, "-f", "prereq.mk", "top_srcdir=.."+"/.."*dir.count("/"), | ||
| hdr, chdir: dir) | ||
| end | ||
| end | ||
|
|
||
| task :default => [:compile, :test] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,16 @@ | ||
| # frozen_string_literal: true | ||
| require 'mkmf' | ||
|
|
||
| config_string("strict_warnflags") {|w| $warnflags += " #{w}"} | ||
|
|
||
| append_cflags("-Wno-compound-token-split-by-macro") if RUBY_VERSION < "2.7." | ||
| have_func("rb_category_warn") | ||
| with_werror("", {:werror => true}) do |opt, | | ||
| have_var("timezone", "time.h", opt) | ||
| have_var("altzone", "time.h", opt) | ||
| if RUBY_VERSION >= "3.3" | ||
| # Pure Ruby implementation; skip C extension build | ||
| File.write("Makefile", dummy_makefile($srcdir).join("")) | ||
| else | ||
| config_string("strict_warnflags") {|w| $warnflags += " #{w}"} | ||
| append_cflags("-Wno-compound-token-split-by-macro") if RUBY_VERSION < "2.7." | ||
| have_func("rb_category_warn") | ||
| with_werror("", {:werror => true}) do |opt, | | ||
| have_var("timezone", "time.h", opt) | ||
| have_var("altzone", "time.h", opt) | ||
| end | ||
| create_makefile('date_core') | ||
| end | ||
|
|
||
| create_makefile('date_core') |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,59 @@ | ||||||||||||||||||||||||||||||||||||||||
| # -*- mode: ruby -*- | ||||||||||||||||||||||||||||||||||||||||
| # Generate lib/date/zonetab.rb from ext/date/zonetab.list | ||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||
| # Usage: ruby -C ext/date generate-zonetab-rb | ||||||||||||||||||||||||||||||||||||||||
| # | ||||||||||||||||||||||||||||||||||||||||
| # This script reads zonetab.list (the same source used to generate zonetab.h | ||||||||||||||||||||||||||||||||||||||||
| # via gperf) and produces the equivalent Ruby hash table. | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| list_path = File.join(__dir__, 'zonetab.list') | ||||||||||||||||||||||||||||||||||||||||
| output_path = File.join(__dir__, '..', '..', 'lib', 'date', 'zonetab.rb') | ||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| entries = {} | ||||||||||||||||||||||||||||||||||||||||
| in_entries = false | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| File.foreach(list_path) do |line| | ||||||||||||||||||||||||||||||||||||||||
| line.chomp! | ||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
| if line == '%%' | ||||||||||||||||||||||||||||||||||||||||
| if in_entries | ||||||||||||||||||||||||||||||||||||||||
| break | ||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||
| in_entries = true | ||||||||||||||||||||||||||||||||||||||||
| next | ||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||
| next unless in_entries | ||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| abbr, offset_expr = line.split(',', 2) | ||||||||||||||||||||||||||||||||||||||||
| next unless offset_expr | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| abbr.strip! | ||||||||||||||||||||||||||||||||||||||||
| offset_expr.strip! | ||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need to strip, as
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| # Evaluate offset expression (e.g., "0*3600", "-5*3600", "-(1*3600+1800)", "16200") | ||||||||||||||||||||||||||||||||||||||||
| offset = eval(offset_expr) | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| entries[abbr] = offset | ||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| sorted = entries.sort_by { |k, _| k } | ||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| max_key_len = sorted.map { |k, _| k.length }.max | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| File.open(output_path, 'w') do |f| | ||||||||||||||||||||||||||||||||||||||||
| f.puts '# frozen_string_literal: true' | ||||||||||||||||||||||||||||||||||||||||
| f.puts | ||||||||||||||||||||||||||||||||||||||||
| f.puts '# Timezone name => UTC offset (seconds) mapping table.' | ||||||||||||||||||||||||||||||||||||||||
| f.puts '# Auto-generated from ext/date/zonetab.list by ext/date/generate-zonetab-rb.' | ||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
| f.puts '# Do not edit manually.' | ||||||||||||||||||||||||||||||||||||||||
| f.puts 'class Date' | ||||||||||||||||||||||||||||||||||||||||
| f.puts ' ZONE_TABLE = {' | ||||||||||||||||||||||||||||||||||||||||
| sorted.each do |abbr, offset| | ||||||||||||||||||||||||||||||||||||||||
| key = abbr.include?(' ') ? %Q("#{abbr}") : %Q("#{abbr}") | ||||||||||||||||||||||||||||||||||||||||
| f.puts " %-#{max_key_len + 3}s => %d," % [key, offset] | ||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Both sides look the same expression.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||
| f.puts ' }.freeze' | ||||||||||||||||||||||||||||||||||||||||
| f.puts 'end' | ||||||||||||||||||||||||||||||||||||||||
| end | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| puts "Generated #{output_path} with #{entries.size} entries." | ||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.