зеркало из https://github.com/github/ruby.git
Add Time#deconstruct_keys
This commit is contained in:
Родитель
63f4a7a1ec
Коммит
eaf2b6c439
5
NEWS.md
5
NEWS.md
|
@ -225,6 +225,10 @@ Note: We're only listing outstanding class updates.
|
|||
* A Struct class can also be initialized with keyword arguments
|
||||
without `keyword_init: true` on `Struct.new` [[Feature #16806]]
|
||||
|
||||
* Time
|
||||
* `Time#deconstruct_keys` is added, allowing to use `Time` instances
|
||||
in pattern-matching expressions [[Feature #19071]]
|
||||
|
||||
* TracePoint
|
||||
* TracePoint#binding now returns `nil` for `c_call`/`c_return` TracePoints.
|
||||
[[Bug #18487]]
|
||||
|
@ -448,3 +452,4 @@ The following deprecated APIs are removed.
|
|||
[Feature #19070]: https://bugs.ruby-lang.org/issues/19070
|
||||
[Bug #19100]: https://bugs.ruby-lang.org/issues/19100
|
||||
[Feature #19135]: https://bugs.ruby-lang.org/issues/19135
|
||||
[Feature #19071]: https://bugs.ruby-lang.org/issues/19071
|
||||
|
|
|
@ -15833,6 +15833,7 @@ time.$(OBJEXT): $(top_srcdir)/internal/compar.h
|
|||
time.$(OBJEXT): $(top_srcdir)/internal/compilers.h
|
||||
time.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
|
||||
time.$(OBJEXT): $(top_srcdir)/internal/gc.h
|
||||
time.$(OBJEXT): $(top_srcdir)/internal/hash.h
|
||||
time.$(OBJEXT): $(top_srcdir)/internal/numeric.h
|
||||
time.$(OBJEXT): $(top_srcdir)/internal/rational.h
|
||||
time.$(OBJEXT): $(top_srcdir)/internal/serial.h
|
||||
|
|
|
@ -1329,4 +1329,18 @@ class TestTime < Test::Unit::TestCase
|
|||
rescue LoadError => e
|
||||
omit "failed to load objspace: #{e.message}"
|
||||
end
|
||||
|
||||
def test_deconstruct_keys
|
||||
t = in_timezone('JST-9') { Time.local(2022, 10, 16, 14, 1, 30, 500) }
|
||||
assert_equal(
|
||||
{year: 2022, month: 10, day: 16, wday: 0, yday: 289,
|
||||
hour: 14, min: 1, sec: 30, subsec: 1/2000r, dst: false, zone: 'JST'},
|
||||
t.deconstruct_keys(nil)
|
||||
)
|
||||
|
||||
assert_equal(
|
||||
{year: 2022, month: 10, sec: 30},
|
||||
t.deconstruct_keys(%i[year month sec nonexistent])
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
108
time.c
108
time.c
|
@ -34,6 +34,7 @@
|
|||
#include "id.h"
|
||||
#include "internal.h"
|
||||
#include "internal/array.h"
|
||||
#include "internal/hash.h"
|
||||
#include "internal/compar.h"
|
||||
#include "internal/numeric.h"
|
||||
#include "internal/rational.h"
|
||||
|
@ -51,6 +52,10 @@ static ID id_local_to_utc, id_utc_to_local, id_find_timezone;
|
|||
static ID id_year, id_mon, id_mday, id_hour, id_min, id_sec, id_isdst;
|
||||
static VALUE str_utc, str_empty;
|
||||
|
||||
// used by deconstruct_keys
|
||||
static VALUE sym_year, sym_month, sym_day, sym_yday, sym_wday;
|
||||
static VALUE sym_hour, sym_min, sym_sec, sym_subsec, sym_dst, sym_zone;
|
||||
|
||||
#define id_quo idQuo
|
||||
#define id_div idDiv
|
||||
#define id_divmod idDivmod
|
||||
|
@ -4834,6 +4839,96 @@ time_to_a(VALUE time)
|
|||
time_zone(time));
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* deconstruct_keys(array_of_names_or_nil) -> hash
|
||||
*
|
||||
* Returns a hash of the name/value pairs, to use in pattern matching.
|
||||
* Possible keys are the same as returned by #to_h.
|
||||
*
|
||||
* Possible usages:
|
||||
*
|
||||
* t = Time.utc(2022, 10, 5, 21, 25, 30)
|
||||
*
|
||||
* if t in wday: 3, day: ..7 # uses deconstruct_keys underneath
|
||||
* puts "first Wednesday of the month"
|
||||
* end
|
||||
* #=> prints "first Wednesday of the month"
|
||||
*
|
||||
* case t
|
||||
* in year: ...2022
|
||||
* puts "too old"
|
||||
* in month: ..9
|
||||
* puts "quarter 1-3"
|
||||
* in wday: 1..5, month:
|
||||
* puts "working day in month #{month}"
|
||||
* end
|
||||
* #=> prints "working day in month 10"
|
||||
*
|
||||
* Note that deconstruction by pattern can also be combined with class check:
|
||||
*
|
||||
* if t in Time(wday: 3, day: ..7)
|
||||
* puts "first Wednesday of the month"
|
||||
* end
|
||||
*
|
||||
*/
|
||||
static VALUE
|
||||
time_deconstruct_keys(VALUE time, VALUE keys)
|
||||
{
|
||||
struct time_object *tobj;
|
||||
VALUE h;
|
||||
long i;
|
||||
|
||||
GetTimeval(time, tobj);
|
||||
MAKE_TM_ENSURE(time, tobj, tobj->vtm.yday != 0);
|
||||
|
||||
if (NIL_P(keys)) {
|
||||
h = rb_hash_new_with_size(11);
|
||||
|
||||
rb_hash_aset(h, sym_year, tobj->vtm.year);
|
||||
rb_hash_aset(h, sym_month, INT2FIX(tobj->vtm.mon));
|
||||
rb_hash_aset(h, sym_day, INT2FIX(tobj->vtm.mday));
|
||||
rb_hash_aset(h, sym_yday, INT2FIX(tobj->vtm.yday));
|
||||
rb_hash_aset(h, sym_wday, INT2FIX(tobj->vtm.wday));
|
||||
rb_hash_aset(h, sym_hour, INT2FIX(tobj->vtm.hour));
|
||||
rb_hash_aset(h, sym_min, INT2FIX(tobj->vtm.min));
|
||||
rb_hash_aset(h, sym_sec, INT2FIX(tobj->vtm.sec));
|
||||
rb_hash_aset(h, sym_subsec,
|
||||
quov(w2v(wmod(tobj->timew, WINT2FIXWV(TIME_SCALE))), INT2FIX(TIME_SCALE)));
|
||||
rb_hash_aset(h, sym_dst, RBOOL(tobj->vtm.isdst));
|
||||
rb_hash_aset(h, sym_zone, time_zone(time));
|
||||
|
||||
return h;
|
||||
}
|
||||
if (UNLIKELY(!RB_TYPE_P(keys, T_ARRAY))) {
|
||||
rb_raise(rb_eTypeError,
|
||||
"wrong argument type %"PRIsVALUE" (expected Array or nil)",
|
||||
rb_obj_class(keys));
|
||||
|
||||
}
|
||||
|
||||
h = rb_hash_new_with_size(RARRAY_LEN(keys));
|
||||
|
||||
for (i=0; i<RARRAY_LEN(keys); i++) {
|
||||
VALUE key = RARRAY_AREF(keys, i);
|
||||
|
||||
if (sym_year == key) rb_hash_aset(h, key, tobj->vtm.year);
|
||||
if (sym_month == key) rb_hash_aset(h, key, INT2FIX(tobj->vtm.mon));
|
||||
if (sym_day == key) rb_hash_aset(h, key, INT2FIX(tobj->vtm.mday));
|
||||
if (sym_yday == key) rb_hash_aset(h, key, INT2FIX(tobj->vtm.yday));
|
||||
if (sym_wday == key) rb_hash_aset(h, key, INT2FIX(tobj->vtm.wday));
|
||||
if (sym_hour == key) rb_hash_aset(h, key, INT2FIX(tobj->vtm.hour));
|
||||
if (sym_min == key) rb_hash_aset(h, key, INT2FIX(tobj->vtm.min));
|
||||
if (sym_sec == key) rb_hash_aset(h, key, INT2FIX(tobj->vtm.sec));
|
||||
if (sym_subsec == key) {
|
||||
rb_hash_aset(h, key, quov(w2v(wmod(tobj->timew, WINT2FIXWV(TIME_SCALE))), INT2FIX(TIME_SCALE)));
|
||||
}
|
||||
if (sym_dst == key) rb_hash_aset(h, key, RBOOL(tobj->vtm.isdst));
|
||||
if (sym_zone == key) rb_hash_aset(h, key, time_zone(time));
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
rb_strftime_alloc(const char *format, size_t format_len, rb_encoding *enc,
|
||||
VALUE time, struct vtm *vtm, wideval_t timew, int gmt)
|
||||
|
@ -5537,6 +5632,18 @@ Init_Time(void)
|
|||
id_isdst = rb_intern_const("isdst");
|
||||
id_find_timezone = rb_intern_const("find_timezone");
|
||||
|
||||
sym_year = ID2SYM(rb_intern_const("year"));
|
||||
sym_month = ID2SYM(rb_intern_const("month"));
|
||||
sym_yday = ID2SYM(rb_intern_const("yday"));
|
||||
sym_wday = ID2SYM(rb_intern_const("wday"));
|
||||
sym_day = ID2SYM(rb_intern_const("day"));
|
||||
sym_hour = ID2SYM(rb_intern_const("hour"));
|
||||
sym_min = ID2SYM(rb_intern_const("min"));
|
||||
sym_sec = ID2SYM(rb_intern_const("sec"));
|
||||
sym_subsec = ID2SYM(rb_intern_const("subsec"));
|
||||
sym_dst = ID2SYM(rb_intern_const("dst"));
|
||||
sym_zone = ID2SYM(rb_intern_const("zone"));
|
||||
|
||||
str_utc = rb_fstring_lit("UTC");
|
||||
rb_gc_register_mark_object(str_utc);
|
||||
str_empty = rb_fstring_lit("");
|
||||
|
@ -5572,6 +5679,7 @@ Init_Time(void)
|
|||
rb_define_method(rb_cTime, "to_s", time_to_s, 0);
|
||||
rb_define_method(rb_cTime, "inspect", time_inspect, 0);
|
||||
rb_define_method(rb_cTime, "to_a", time_to_a, 0);
|
||||
rb_define_method(rb_cTime, "deconstruct_keys", time_deconstruct_keys, 1);
|
||||
|
||||
rb_define_method(rb_cTime, "+", time_plus, 1);
|
||||
rb_define_method(rb_cTime, "-", time_minus, 1);
|
||||
|
|
1
timev.rb
1
timev.rb
|
@ -201,6 +201,7 @@
|
|||
# - #getlocal: Returns a new time converted to local time.
|
||||
# - #utc (aliased as #gmtime): Converts time to UTC in place.
|
||||
# - #localtime: Converts time to local time in place.
|
||||
# - #deconstruct_keys: Returns a hash of time components used in pattern-matching.
|
||||
#
|
||||
# === Methods for Rounding
|
||||
#
|
||||
|
|
Загрузка…
Ссылка в новой задаче