diff --git a/.document b/.document index 5494bcc7feea95..ec2fa093261427 100644 --- a/.document +++ b/.document @@ -24,6 +24,7 @@ pack.rb ractor.rb string.rb timev.rb +thread_sync.rb trace_point.rb warning.rb diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 87f33d7045c0a7..c05a98e306c73d 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -8,3 +8,13 @@ # Enable Style/StringLiterals cop for RubyGems/Bundler d7ffd3fea402239b16833cc434404a7af82d44f3 + +# [ruby/digest] Revert tab-expansion in external files +48b09aae7ec5632209229dcc294dd0d75a93a17f +8a65cf3b61c60e4cb886f59a73ff6db44364bfa9 +39dc9f9093901d40d2998653948d5da38b18ee2c + +# [ruby/io-nonblock] Revert tab expansion +f28287d34c03f472ffe90ea262bdde9affd4b965 +0d842fecb4f75ab3b1d4097ebdb8e88f51558041 +4ba2c66761d6a293abdfba409241d31063cefd62 diff --git a/NEWS.md b/NEWS.md index fdb58e4bb7fb45..d3fee75302d250 100644 --- a/NEWS.md +++ b/NEWS.md @@ -96,6 +96,9 @@ Note that each entry is kept to a minimum, see links for details. Note: We're only listing outstanding class updates. +* Enumerator + * Enumerator.product has been added. Enumerator::Product is the implementation. [[Feature #18685]] + * Hash * Hash#shift now always returns nil if the hash is empty, instead of returning the default value or @@ -268,5 +271,6 @@ The following deprecated APIs are removed. [Feature #18598]: https://bugs.ruby-lang.org/issues/18598 [Bug #18625]: https://bugs.ruby-lang.org/issues/18625 [Bug #18633]: https://bugs.ruby-lang.org/issues/18633 +[Feature #18685]: https://bugs.ruby-lang.org/issues/18685 [Bug #18782]: https://bugs.ruby-lang.org/issues/18782 [Feature #18788]: https://bugs.ruby-lang.org/issues/18788 diff --git a/array.c b/array.c index b0c4cee0bf64b3..b2ebf3c0e9ebee 100644 --- a/array.c +++ b/array.c @@ -967,7 +967,7 @@ rb_ec_ary_new_from_values(rb_execution_context_t *ec, long n, const VALUE *elts) } VALUE -rb_ary_tmp_new(long capa) +rb_ary_hidden_new(long capa) { VALUE ary = ary_new(0, capa); rb_ary_transient_heap_evacuate(ary, TRUE); @@ -975,12 +975,11 @@ rb_ary_tmp_new(long capa) } VALUE -rb_ary_tmp_new_fill(long capa) +rb_ary_hidden_new_fill(long capa) { - VALUE ary = ary_new(0, capa); + VALUE ary = rb_ary_hidden_new(capa); ary_memfill(ary, 0, capa, Qnil); ARY_SET_LEN(ary, capa); - rb_ary_transient_heap_evacuate(ary, TRUE); return ary; } @@ -1025,18 +1024,10 @@ rb_ary_memsize(VALUE ary) } } -static inline void -ary_discard(VALUE ary) -{ - rb_ary_free(ary); - RBASIC(ary)->flags |= RARRAY_EMBED_FLAG; - RBASIC(ary)->flags &= ~(RARRAY_EMBED_LEN_MASK | RARRAY_TRANSIENT_FLAG); -} - static VALUE ary_make_shared(VALUE ary) { - assert(!ARY_EMBED_P(ary)); + assert(USE_RVARGC || !ARY_EMBED_P(ary)); ary_verify(ary); if (ARY_SHARED_P(ary)) { @@ -1046,21 +1037,38 @@ ary_make_shared(VALUE ary) return ary; } else if (OBJ_FROZEN(ary)) { - rb_ary_transient_heap_evacuate(ary, TRUE); - ary_shrink_capa(ary); + if (!ARY_EMBED_P(ary)) { + rb_ary_transient_heap_evacuate(ary, TRUE); + ary_shrink_capa(ary); + } return ary; } else { - long capa = ARY_CAPA(ary), len = RARRAY_LEN(ary); - const VALUE *ptr; + rb_ary_transient_heap_evacuate(ary, TRUE); + + long capa = ARY_CAPA(ary); + long len = RARRAY_LEN(ary); + + /* Shared roots cannot be embedded because the reference count + * (refcnt) is stored in as.heap.aux.capa. */ VALUE shared = ary_alloc_heap(0); - rb_ary_transient_heap_evacuate(ary, TRUE); - ptr = ARY_HEAP_PTR(ary); + if (ARY_EMBED_P(ary)) { + /* Cannot use ary_heap_alloc because we don't want to allocate + * on the transient heap. */ + VALUE *ptr = ALLOC_N(VALUE, capa); + ARY_SET_PTR(shared, ptr); + ary_memcpy(shared, 0, len, RARRAY_PTR(ary)); + + FL_UNSET_EMBED(ary); + ARY_SET_HEAP_LEN(ary, len); + ARY_SET_PTR(ary, ptr); + } + else { + ARY_SET_PTR(shared, RARRAY_PTR(ary)); + } - FL_UNSET_EMBED(shared); ARY_SET_LEN(shared, capa); - ARY_SET_PTR(shared, ptr); ary_mem_clear(shared, len, capa - len); FL_SET_SHARED_ROOT(shared); ARY_SET_SHARED_ROOT_REFCNT(shared, 1); @@ -1327,7 +1335,9 @@ ary_make_partial(VALUE ary, VALUE klass, long offset, long len) assert(len >= 0); assert(offset+len <= RARRAY_LEN(ary)); - if (ary_embeddable_p(len)) { + const size_t rarray_embed_capa_max = (sizeof(struct RArray) - offsetof(struct RArray, as.ary)) / sizeof(VALUE); + + if ((size_t)len <= rarray_embed_capa_max && ary_embeddable_p(len)) { VALUE result = ary_alloc_embed(klass, len); ary_memcpy(result, 0, len, RARRAY_CONST_PTR_TRANSIENT(ary) + offset); ARY_SET_EMBED_LEN(result, len); @@ -5109,7 +5119,7 @@ rb_ary_concat_multi(int argc, VALUE *argv, VALUE ary) } else if (argc > 1) { int i; - VALUE args = rb_ary_tmp_new(argc); + VALUE args = rb_ary_hidden_new(argc); for (i = 0; i < argc; i++) { rb_ary_concat(args, argv[i]); } @@ -6937,9 +6947,6 @@ rb_ary_cycle(int argc, VALUE *argv, VALUE ary) return Qnil; } -#define tmpary(n) rb_ary_tmp_new(n) -#define tmpary_discard(a) (ary_discard(a), RBASIC_SET_CLASS_RAW(a, rb_cArray)) - /* * Build a ruby array of the corresponding values and yield it to the * associated block. @@ -7634,7 +7641,7 @@ static VALUE rb_ary_product(int argc, VALUE *argv, VALUE ary) { int n = argc+1; /* How many arrays we're operating on */ - volatile VALUE t0 = tmpary(n); + volatile VALUE t0 = rb_ary_hidden_new(n); volatile VALUE t1 = Qundef; VALUE *arrays = RARRAY_PTR(t0); /* The arrays we're computing the product of */ int *counters = ALLOCV_N(int, t1, n); /* The current position in each one */ @@ -7711,8 +7718,8 @@ rb_ary_product(int argc, VALUE *argv, VALUE ary) counters[m]++; } } + done: - tmpary_discard(t0); ALLOCV_END(t1); return NIL_P(result) ? ary : result; diff --git a/bootstraptest/test_io.rb b/bootstraptest/test_io.rb index c6c3772d3696b0..ff2649769656b4 100644 --- a/bootstraptest/test_io.rb +++ b/bootstraptest/test_io.rb @@ -1,3 +1,4 @@ +/freebsd/ =~ RUBY_PLATFORM or assert_finish 5, %q{ r, w = IO.pipe t1 = Thread.new { r.sysread(1) } diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb index 7158486d5048ff..966a5f30021499 100644 --- a/bootstraptest/test_yjit.rb +++ b/bootstraptest/test_yjit.rb @@ -1224,6 +1224,19 @@ def foo(&block) [foo {1}, foo {2}, foo {42}] } +# test calling without block param +assert_equal '[1, false, 2, false]', %q{ + def bar + block_given? && yield + end + + def foo(&block) + bar(&block) + end + + [foo { 1 }, foo, foo { 2 }, foo] +} + # test calling block param failing assert_equal '42', %q{ def foo(&block) diff --git a/class.c b/class.c index 4306b7c0f34e70..54d9e6e17795dc 100644 --- a/class.c +++ b/class.c @@ -507,7 +507,7 @@ rb_mod_init_copy(VALUE clone, VALUE orig) VALUE p = RCLASS_SUPER(orig); VALUE orig_origin = RCLASS_ORIGIN(orig); VALUE prev_clone_p = clone; - VALUE origin_stack = rb_ary_tmp_new(2); + VALUE origin_stack = rb_ary_hidden_new(2); VALUE origin[2]; VALUE clone_p = 0; long origin_len; @@ -1250,7 +1250,7 @@ do_include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super RCLASS_SET_INCLUDER(iclass, klass); add_subclass = TRUE; if (module != RCLASS_ORIGIN(module)) { - if (!origin_stack) origin_stack = rb_ary_tmp_new(2); + if (!origin_stack) origin_stack = rb_ary_hidden_new(2); VALUE origin[2] = {iclass, RCLASS_ORIGIN(module)}; rb_ary_cat(origin_stack, origin, 2); } @@ -2310,7 +2310,7 @@ rb_get_kwargs(VALUE keyword_hash, const ID *table, int required, int optional, V continue; } } - if (NIL_P(missing)) missing = rb_ary_tmp_new(1); + if (NIL_P(missing)) missing = rb_ary_hidden_new(1); rb_ary_push(missing, keyword); } if (!NIL_P(missing)) { diff --git a/common.mk b/common.mk index aeb87dfb553c71..4c49690e4abcdf 100644 --- a/common.mk +++ b/common.mk @@ -1062,6 +1062,7 @@ BUILTIN_RB_SRCS = \ $(srcdir)/kernel.rb \ $(srcdir)/ractor.rb \ $(srcdir)/timev.rb \ + $(srcdir)/thread_sync.rb \ $(srcdir)/nilclass.rb \ $(srcdir)/prelude.rb \ $(srcdir)/gem_prelude.rb \ @@ -9447,6 +9448,7 @@ miniinit.$(OBJEXT): {$(VPATH)}st.h miniinit.$(OBJEXT): {$(VPATH)}subst.h miniinit.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h miniinit.$(OBJEXT): {$(VPATH)}thread_native.h +miniinit.$(OBJEXT): {$(VPATH)}thread_sync.rb miniinit.$(OBJEXT): {$(VPATH)}timev.rb miniinit.$(OBJEXT): {$(VPATH)}trace_point.rb miniinit.$(OBJEXT): {$(VPATH)}vm_core.h @@ -15230,6 +15232,7 @@ thread.$(OBJEXT): {$(VPATH)}backward/2/limits.h thread.$(OBJEXT): {$(VPATH)}backward/2/long_long.h thread.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h thread.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h +thread.$(OBJEXT): {$(VPATH)}builtin.h thread.$(OBJEXT): {$(VPATH)}config.h thread.$(OBJEXT): {$(VPATH)}debug.h thread.$(OBJEXT): {$(VPATH)}debug_counter.h @@ -15412,6 +15415,8 @@ thread.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).c thread.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h thread.$(OBJEXT): {$(VPATH)}thread_native.h thread.$(OBJEXT): {$(VPATH)}thread_sync.c +thread.$(OBJEXT): {$(VPATH)}thread_sync.rb +thread.$(OBJEXT): {$(VPATH)}thread_sync.rbinc thread.$(OBJEXT): {$(VPATH)}timev.h thread.$(OBJEXT): {$(VPATH)}vm_core.h thread.$(OBJEXT): {$(VPATH)}vm_debug.h diff --git a/compile.c b/compile.c index c17c97adbba885..6a9ed2a5d09453 100644 --- a/compile.c +++ b/compile.c @@ -313,7 +313,7 @@ static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NOD LABEL_REF(le); \ LABEL_REF(lc); \ if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) \ - RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_tmp_new(3)); \ + RB_OBJ_WRITE(iseq, &ISEQ_COMPILE_DATA(iseq)->catch_table_ary, rb_ary_hidden_new(3)); \ rb_ary_push(ISEQ_COMPILE_DATA(iseq)->catch_table_ary, freeze_hide_obj(_e)); \ } while (0) @@ -627,7 +627,7 @@ decl_branch_base(rb_iseq_t *iseq, const NODE *node, const char *type) VALUE branches; if (NIL_P(branch_base)) { - branch_base = rb_ary_tmp_new(6); + branch_base = rb_ary_hidden_new(6); rb_hash_aset(structure, key, branch_base); rb_ary_push(branch_base, ID2SYM(rb_intern(type))); rb_ary_push(branch_base, INT2FIX(first_lineno)); @@ -675,7 +675,7 @@ add_trace_branch_coverage(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NODE *n long counter_idx; if (NIL_P(branch)) { - branch = rb_ary_tmp_new(6); + branch = rb_ary_hidden_new(6); rb_hash_aset(branches, key, branch); rb_ary_push(branch, ID2SYM(rb_intern(type))); rb_ary_push(branch, INT2FIX(first_lineno)); @@ -1743,7 +1743,7 @@ iseq_set_arguments_keywords(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *node = args->kw_args; struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq); struct rb_iseq_param_keyword *keyword; - const VALUE default_values = rb_ary_tmp_new(1); + const VALUE default_values = rb_ary_hidden_new(1); const VALUE complex_mark = rb_str_tmp_new(0); int kw = 0, rkw = 0, di = 0, i; @@ -1847,7 +1847,7 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *cons if (args->opt_args) { const NODE *node = args->opt_args; LABEL *label; - VALUE labels = rb_ary_tmp_new(1); + VALUE labels = rb_ary_hidden_new(1); VALUE *opt_table; int i = 0, j; @@ -4369,7 +4369,7 @@ compile_array(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int pop if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_ary_len) { /* The literal contains only optimizable elements, or the subarray is long enough */ - VALUE ary = rb_ary_tmp_new(count); + VALUE ary = rb_ary_hidden_new(count); /* Create a hidden array */ for (; count; count--, node = node->nd_next) @@ -4420,7 +4420,7 @@ static int compile_array_1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node) { if (static_literal_node_p(node, iseq)) { - VALUE ary = rb_ary_tmp_new(1); + VALUE ary = rb_ary_hidden_new(1); rb_ary_push(ary, static_literal_value(node, iseq)); OBJ_FREEZE(ary); @@ -4517,7 +4517,7 @@ compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int meth if ((first_chunk && stack_len == 0 && !node_tmp) || count >= min_tmp_hash_len) { /* The literal contains only optimizable elements, or the subsequence is long enough */ - VALUE ary = rb_ary_tmp_new(count); + VALUE ary = rb_ary_hidden_new(count); /* Create a hidden hash */ for (; count; count--, node = node->nd_next->nd_next) { @@ -4837,7 +4837,8 @@ struct masgn_state { }; static int -add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn) { +add_masgn_lhs_node(struct masgn_state *state, int lhs_pos, const NODE *line_node, int argc, INSN *before_insn) +{ if (!state) { rb_bug("no masgn_state"); } @@ -12077,7 +12078,7 @@ ibf_dump_iseq_list_i(st_data_t key, st_data_t val, st_data_t ptr) static void ibf_dump_iseq_list(struct ibf_dump *dump, struct ibf_header *header) { - VALUE offset_list = rb_ary_tmp_new(dump->iseq_table->num_entries); + VALUE offset_list = rb_ary_hidden_new(dump->iseq_table->num_entries); struct ibf_dump_iseq_list_arg args; args.dump = dump; @@ -12349,7 +12350,7 @@ ibf_load_object_array(const struct ibf_load *load, const struct ibf_object_heade const long len = (long)ibf_load_small_value(load, &reading_pos); - VALUE ary = header->internal ? rb_ary_tmp_new(len) : rb_ary_new_capa(len); + VALUE ary = header->internal ? rb_ary_hidden_new(len) : rb_ary_new_capa(len); int i; for (i=0; icurrent_buffer->obj_table; - VALUE offset_list = rb_ary_tmp_new(obj_table->num_entries); + VALUE offset_list = rb_ary_hidden_new(obj_table->num_entries); struct ibf_dump_object_list_arg args; args.dump = dump; diff --git a/configure.ac b/configure.ac index 4fe1623966bae4..9ed0c1ef9e2ca9 100644 --- a/configure.ac +++ b/configure.ac @@ -3011,6 +3011,14 @@ STATIC= : ${LDFLAGS=""} : ${LIBPATHENV=DYLD_FALLBACK_LIBRARY_PATH} : ${PRELOADENV=DYLD_INSERT_LIBRARIES} + AS_IF([test x"$enable_shared" = xyes], [ + # Resolve symbols from libruby.dylib when --enable-shared + EXTDLDFLAGS='$(LIBRUBYARG_SHARED)' + ], [test "x$EXTSTATIC" = x], [ + # When building exts as bundles, a mach-o bundle needs to know its loader + # program to bind symbols from the ruby executable + EXTDLDFLAGS="-bundle_loader '\$(BUILTRUBY)'" + ]) rb_cv_dlopen=yes], [aix*], [ : ${LDSHARED='$(CC)'} AS_IF([test "$GCC" = yes], [ @@ -3736,7 +3744,7 @@ CARGO= CARGO_BUILD_ARGS= YJIT_LIBS= AS_CASE(["${YJIT_SUPPORT}"], -[yes|dev], [ +[yes|dev|stats|dev_nodebug], [ AS_IF([test x"$enable_jit_support" = "xno"], AC_MSG_ERROR([--disable-jit-support but --enable-yjit. YJIT requires JIT support]) ) @@ -3744,16 +3752,31 @@ AS_CASE(["${YJIT_SUPPORT}"], AS_IF([test x"$RUSTC" = "xno"], AC_MSG_ERROR([rustc is required. Installation instructions available at https://www.rust-lang.org/tools/install]) ) - AS_IF([test x"$YJIT_SUPPORT" = "xyes"], - [rb_rust_target_subdir=release - CARGO_BUILD_ARGS='--release'], - [rb_rust_target_subdir=debug - CARGO_BUILD_ARGS='--features stats,disasm,asm_comments' + + AS_CASE(["${YJIT_SUPPORT}"], + [yes], [ + rb_rust_target_subdir=release + ], + [dev], [ + rb_rust_target_subdir=debug + CARGO_BUILD_ARGS='--features stats,disasm,asm_comments' + AC_DEFINE(RUBY_DEBUG, 1) + ], + [dev_nodebug], [ + rb_rust_target_subdir=dev_nodebug + CARGO_BUILD_ARGS='--profile dev_nodebug --features stats,disasm,asm_comments' + ], + [stats], [ + rb_rust_target_subdir=stats + CARGO_BUILD_ARGS='--profile stats --features stats' + ]) + + AS_IF([test -n "${CARGO_BUILD_ARGS}"], [ AC_CHECK_TOOL(CARGO, [cargo], [no]) AS_IF([test x"$CARGO" = "xno"], AC_MSG_ERROR([cargo is required. Installation instructions available at https://www.rust-lang.org/tools/install]) - ) - AC_DEFINE(RUBY_DEBUG, 1)]) + ])) + YJIT_LIBS="yjit/target/${rb_rust_target_subdir}/libyjit.a" YJIT_OBJ='yjit.$(OBJEXT)' AC_DEFINE(USE_YJIT, 1) diff --git a/cont.c b/cont.c index 590d6c250f4c9a..8a9aded7133318 100644 --- a/cont.c +++ b/cont.c @@ -1316,7 +1316,7 @@ cont_capture(volatile int *volatile stat) entry = cont->ensure_array = ALLOC_N(rb_ensure_entry_t,size+1); for (p=th->ec->ensure_list; p; p=p->next) { if (!p->entry.marker) - p->entry.marker = rb_ary_tmp_new(0); /* dummy object */ + p->entry.marker = rb_ary_hidden_new(0); /* dummy object */ *entry++ = p->entry; } entry->marker = 0; diff --git a/debug.c b/debug.c index 81b03c540f783c..3af7f26275033a 100644 --- a/debug.c +++ b/debug.c @@ -348,7 +348,8 @@ setup_debug_log_filter(void) if (*str == '-') { debug_log.filters[i].negative = true; str++; - } else if (*str == '+') { + } + else if (*str == '+') { // negative is false on default. str++; } diff --git a/doc/.document b/doc/.document index 03d332367ca974..5ef2d99651404b 100644 --- a/doc/.document +++ b/doc/.document @@ -5,3 +5,4 @@ contributing NEWS syntax optparse +rdoc diff --git a/doc/contributing/testing_ruby.md b/doc/contributing/testing_ruby.md index dd46ba5dbce757..6247686efcf443 100644 --- a/doc/contributing/testing_ruby.md +++ b/doc/contributing/testing_ruby.md @@ -20,6 +20,13 @@ We can run any of the make scripts [in parallel](building_ruby.md#label-Running+ make btest OPTS=-v ``` + To run individual bootstrap tests, we can either specify a list of filenames or use the `--sets` flag in the variable `BTESTS`: + + ``` + make btest BTESTS="bootstraptest/test_fork.rb bootstraptest/tes_gc.rb" + make btest BTESTS="--sets=fork,gc" + ``` + If we want to run the bootstrap test suite on Ruby (not Miniruby), we can use: ``` diff --git a/doc/rdoc/markup_reference.rb b/doc/rdoc/markup_reference.rb new file mode 100644 index 00000000000000..49ad996c2d22e0 --- /dev/null +++ b/doc/rdoc/markup_reference.rb @@ -0,0 +1,1013 @@ +require 'rdoc' + +# \Class \RDoc::MarkupReference exists only to provide a suitable home +# for a reference document for \RDoc markup. +# +# All objects defined in this class -- classes, modules, methods, aliases, +# attributes, and constants -- are solely for illustrating \RDoc markup, +# and have no other legitimate use. +# +# = \RDoc Markup Reference +# +# Notes: +# +# - Examples in this reference are Ruby code and comments; +# certain differences from other sources +# (such as C code and comments) are noted. +# - An example that shows rendered HTML output +# displays that output in a blockquote: +# +# Rendered HTML: +# >>> +# Some stuff +# +# \RDoc-generated documentation is derived from and controlled by: +# +# - Single-line or multi-line comments that precede certain definitions; +# see {Markup in Comments}[rdoc-ref:RDoc::MarkupReference@Markup+in+Comments]. +# - \RDoc directives in trailing comments (on the same line as code); +# see :nodoc:, :doc:, and :notnew. +# - \RDoc directives in single-line comments; +# see other {Directives}[rdoc-ref:RDoc::MarkupReference@Directives]. +# - The Ruby code itself; +# see {Documentation Derived from Ruby Code}[rdoc-ref:RDoc::MarkupReference@Documentation+Derived+from+Ruby+Code] +# +# == Markup in Comments +# +# A single-line or multi-line comment that immediately precedes +# the definition of a class, module, method, alias, constant, or attribute +# becomes the documentation for that defined object. +# +# (\RDoc ignores other such comments that do not precede definitions.) +# +# === Margins +# +# In a multi-line comment, +# \RDoc looks for the comment's natural left margin, +# which becomes the base margin for the comment +# and is the initial current margin for for the comment. +# +# The current margin can change, and does so, for example in a list. +# +# === Blocks +# +# It's convenient to think of markup input as a sequence of _blocks_, +# such as: +# +# - {Paragraphs}[rdoc-ref:RDoc::MarkupReference@Paragraphs]. +# - {Verbatim text blocks}[rdoc-ref:RDoc::MarkupReference@Verbatim+Text+Blocks]. +# - {Code blocks}[rdoc-ref:RDoc::MarkupReference@Code+Blocks]. +# - {Block quotes}[rdoc-ref:RDoc::MarkupReference@Block+Quotes]. +# - {Bullet lists}[rdoc-ref:RDoc::MarkupReference@Bullet+Lists]. +# - {Numbered lists}[rdoc-ref:RDoc::MarkupReference@Numbered+Lists]. +# - {Lettered lists}[rdoc-ref:RDoc::MarkupReference@Lettered+Lists]. +# - {Labeled lists}[rdoc-ref:RDoc::MarkupReference@Labeled+Lists]. +# - {Headings}[rdoc-ref:RDoc::MarkupReference@Headings]. +# - {Horizontal rules}[rdoc-ref:RDoc::MarkupReference@Horizontal+Rules]. +# - {Directives}[rdoc-ref:RDoc::MarkupReference@Directives]. +# +# All of these except paragraph blocks are distinguished by indentation, +# or by unusual initial or embedded characters. +# +# ==== Paragraphs +# +# A paragraph consists of one or more non-empty lines of ordinary text, +# each beginning at the current margin. +# +# Note: Here, ordinary text means text that is not identified +# by indentation, or by unusual initial or embedded characters. +# See below. +# +# Paragraphs are separated by one or more empty lines. +# +# Example input: +# +# # \RDoc produces HTML and command-line documentation for Ruby projects. +# # \RDoc includes the rdoc and ri tools for generating and displaying +# # documentation from the command-line. +# # +# # You'll love it. +# +# Rendered HTML: +# >>> +# \RDoc produces HTML and command-line documentation for Ruby projects. +# \RDoc includes the rdoc and ri tools for generating and displaying +# documentation from the command-line. +# +# You'll love it. +# +# A paragraph may contain nested blocks, including: +# +# - Verbatim text blocks. +# - Code blocks. +# - Block quotes. +# - Lists of any type. +# - Headings. +# - Horizontal rules. +# +# ==== Verbatim Text Blocks +# +# Text indented farther than the current margin becomes a verbatim text block +# (or a code block, described next). +# In the rendered HTML, such text: +# +# - Is indented. +# - Has a contrasting background color. +# +# The verbatim text block ends at the first line beginning at the current margin. +# +# Example input: +# +# # This is not verbatim text. +# # +# # This is verbatim text. +# # Whitespace is honored. # See? +# # Whitespace is honored. # See? +# # +# # This is still the same verbatim text block. +# # +# # This is not verbatim text. +# +# Rendered HTML: +# >>> +# This is not verbatim text. +# +# This is verbatim text. +# Whitespace is honored. # See? +# Whitespace is honored. # See? +# +# This is still the same verbatim text block. +# +# This is not verbatim text. +# +# ==== Code Blocks +# +# A special case of verbatim text is the code block, +# which is merely verbatim text that \RDoc recognizes as Ruby code: +# +# In the rendered HTML, the code block: +# +# - Is indented. +# - Has a contrasting background color. +# - Has syntax highlighting. +# +# Example input: +# +# Consider this method: +# +# def foo(name = '', value = 0) +# @name = name # Whitespace is still honored. +# @value = value +# end +# +# +# Rendered HTML: +# >>> +# Consider this method: +# +# def foo(name = '', value = 0) +# @name = name # Whitespace is still honored. +# @value = value +# end +# +# Pro tip: If your indented Ruby code does not get highlighted, +# it may contain a syntax error. +# +# ==== Block Quotes +# +# You can use the characters >>> (unindented), +# followed by indented text, to treat the text +# as a {block quote}[https://en.wikipedia.org/wiki/Block_quotation]: +# +# Example input: +# +# >>> +# Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer +# commodo quam iaculis massa posuere, dictum fringilla justo pulvinar. +# Quisque turpis erat, pharetra eu dui at, sollicitudin accumsan nulla. +# +# Aenean congue ligula eu ligula molestie, eu pellentesque purus +# faucibus. In id leo non ligula condimentum lobortis. Duis vestibulum, +# diam in pellentesque aliquet, mi tellus placerat sapien, id euismod +# purus magna ut tortor. +# +# Rendered HTML: +# +# >>> +# Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer +# commodo quam iaculis massa posuere, dictum fringilla justo pulvinar. +# Quisque turpis erat, pharetra eu dui at, sollicitudin accumsan nulla. +# +# Aenean congue ligula eu ligula molestie, eu pellentesque purus +# faucibus. In id leo non ligula condimentum lobortis. Duis vestibulum, +# diam in pellentesque aliquet, mi tellus placerat sapien, id euismod +# purus magna ut tortor. +# +# A block quote may contain nested blocks, including: +# +# - Other block quotes. +# - Paragraphs. +# - Verbatim text blocks. +# - Code blocks. +# - Lists of any type. +# - Headings. +# - Horizontal rules. +# +# Note that, unlike verbatim text, single newlines are not honored, +# but that a double newline begins a new paragraph in the block quote. +# +# ==== Lists +# +# Each type of list item is marked by a special beginning: +# +# - Bullet list item: Begins with a hyphen or asterisk. +# - Numbered list item: Begins with digits and a period. +# - Lettered list item: Begins with an alphabetic character and a period. +# - Labeled list item: Begins with one of: +# - Square-bracketed text. +# - A word followed by two colons. +# +# A list begins with a list item and continues, even across blank lines, +# as long as list items of the same type are found at the same indentation level. +# +# A new list resets the current margin inward. +# Additional lines of text aligned at that margin +# are part of the continuing list item. +# +# A list item may be continued on additional lines that are aligned +# with the first line. See examples below. +# +# A list item may contain nested blocks, including: +# +# - Other lists of any type. +# - Paragraphs. +# - Verbatim text blocks. +# - Code blocks. +# - Block quotes. +# - Headings. +# - Horizontal rules. +# +# ===== Bullet Lists +# +# A bullet list item begins with a hyphen or asterisk. +# +# Example input: +# +# # - An item. +# # - Another. +# # - An item spanning +# # multiple lines. +# # +# # * Yet another. +# # - Last one. +# +# Rendered HTML: +# >>> +# - An item. +# - Another. +# - An item spanning +# multiple lines. +# +# * Yet another. +# - Last one. +# +# ===== Numbered Lists +# +# A numbered list item begins with digits and a period. +# +# The items are automatically re-numbered. +# +# Example input: +# +# # 100. An item. +# # 10. Another. +# # 1. An item spanning +# # multiple lines. +# # +# # 1. Yet another. +# # 1000. Last one. +# +# Rendered HTML: +# >>> +# 100. An item. +# 10. Another. +# 1. An item spanning +# multiple lines. +# +# 1. Yet another. +# 1000. Last one. +# +# ===== Lettered Lists +# +# A numbered list item begins with a letters and a period. +# +# The items are automatically "re-lettered." +# +# Example input: +# +# # z. An item. +# # y. Another. +# # x. An item spanning +# # multiple lines. +# # +# # x. Yet another. +# # a. Last one. +# +# Rendered HTML: +# >>> +# z. An item. +# y. Another. +# +# x. Yet another. +# a. Last one. +# +# ===== Labeled Lists +# +# A labeled list item begins with one of: +# +# - Square-bracketed text: the label and text are on two lines. +# - A word followed by two colons: the label and text are on the same line. +# +# Example input: +# +# # [foo] An item. +# # bat:: Another. +# # [bag] An item spanning +# # multiple lines. +# # +# # [bar baz] Yet another. +# # bam:: Last one. +# +# Rendered HTML: +# >>> +# [foo] An item. +# bat:: Another. +# [bag] An item spanning +# multiple lines. +# +# [bar baz] Yet another. +# bam:: Last one. +# +# ==== Headings +# +# A heading begins with up to six equal-signs, followed by heading text. +# Whitespace between those and the heading text is optional. +# +# Examples: +# +# # = Section 1 +# # == Section 1.1 +# # === Section 1.1.1 +# # === Section 1.1.2 +# # == Section 1.2 +# # = Section 2 +# # = Foo +# # == Bar +# # === Baz +# # ==== Bam +# # ===== Bat +# # ====== Bad +# # ============Still a Heading (Level 6) +# # \== Not a Heading +# +# ==== Horizontal Rules +# +# A horizontal rule begins with three or more hyphens. +# +# Example input: +# +# # ------ +# # Stuff between. +# # +# # \--- Not a horizontal rule. +# # +# # -- Also not a horizontal rule. +# # +# # --- +# +# Rendered HTML: +# >>> +# ------ +# Stuff between. +# +# \--- Not a horizontal rule. +# +# -- Also not a horizontal rule. +# +# --- +# +# ==== Directives +# +# ===== Directives for Allowing or Suppressing Documentation +# +# - # :stopdoc:: +# +# - Appears on a line by itself. +# - Specifies that \RDoc should ignore markup +# until next :startdoc: directive or end-of-file. +# +# - # :startdoc:: +# +# - Appears on a line by itself. +# - Specifies that \RDoc should resume parsing markup. +# +# - # :enddoc:: +# +# - Appears on a line by itself. +# - Specifies that \RDoc should ignore markup to end-of-file +# regardless of other directives. +# +# - # :nodoc:: +# +# - Appended to a line of code +# that defines a class, module, method, alias, constant, or attribute. +# - Specifies that the defined object should not be documented. +# +# - # :nodoc: all: +# +# - Appended to a line of code +# that defines a class or module. +# - Specifies that the class or module should not be documented. +# By default, however, a nested class or module _will_ be documented. +# +# - # :doc:: +# +# - Appended to a line of code +# that defines a class, module, method, alias, constant, or attribute. +# - Specifies the defined object should be documented, even if otherwise +# would not be documented. +# +# - # :notnew: (aliased as :not_new: and :not-new:): +# +# - Appended to a line of code +# that defines instance method +initialize+. +# - Specifies that singleton method +new+ should not be documented. +# By default, Ruby fakes a corresponding singleton method +new+, +# which \RDoc includes in the documentation. +# Note that instance method +initialize+ is private, and so by default +# is not documented. +# +# For Ruby code, but not for other \RDoc sources, +# there is a shorthand for :stopdoc: and :startdoc:: +# +# # Documented. +# #-- +# # Not documented. +# #++ +# # Documented. +# +# For C code, any of directives :startdoc:, :enddoc:, +# and :nodoc: may appear in a stand-alone comment: +# +# /* :startdoc: */ +# /* :stopdoc: */ +# /* :enddoc: */ +# +# ===== Directive for Specifying \RDoc Source Format +# +# - # :markup: _type_: +# +# - Appears on a line by itself. +# - Specifies the format for the \RDoc input; +# parameter +type+ is one of +markdown+, +rd+, +rdoc+, +tomdoc+. +# +# ===== Directives for HTML Output +# +# - # :title: _text_: +# +# - Appears on a line by itself. +# - Specifies the title for the HTML output. +# +# - # :main: _filename_: +# - Appears on a line by itself. +# - Specifies the HTML file to be displayed first. +# +# ===== Directives for Method Documentation +# +# - # :call-seq:: +# +# - Appears on a line by itself. +# - Specifies the calling sequence to be reported in the HTML, +# overriding the actual calling sequence in the code. +# See method #call_seq_directive. +# +# Note that \RDoc can build the calling sequence for a Ruby-coded method, +# but not for other languages. +# You may want to override that by explicitly giving a :call-seq: +# directive if you want to include: +# +# - A return type, which is not automatically inferred. +# - Multiple calling sequences. +# +# For C code, the directive may appear in a stand-alone comment. +# +# - # :args: _arg_names_ (aliased as :arg:): +# +# - Appears on a line by itself. +# - Specifies the arguments to be reported in the HTML, +# overriding the actual arguments in the code. +# See method #args_directive. +# +# - # :yields: _arg_names_ (aliased as :yield:): +# +# - Appears on a line by itself. +# - Specifies the yield arguments to be reported in the HTML, +# overriding the actual yield in the code. +# See method #yields_directive. +# +# ===== Directives for Organizing Documentation +# +# By default, \RDoc groups: +# +# - Singleton methods together in alphabetical order. +# - Instance methods and their aliases together in alphabetical order. +# - Attributes and their aliases together in alphabetical order. +# +# You can use directives to modify those behaviors. +# +# - # :section: _section_title_: +# +# - Appears on a line by itself. +# - Specifies that following methods are to be grouped into the section +# with the given section_title, +# or into the default section if no title is given. +# The directive remains in effect until another such directive is given, +# but may be temporarily overridden by directive :category:. +# See below. +# +# The comment block containing this directive: +# +# - Must be separated by a blank line from the documentation for the next item. +# - May have one or more lines preceding the directive. +# These will be removed, along with any trailing lines that match them. +# Such lines may be visually helpful. +# - Lines of text that are not so removed become the descriptive text +# for the section. +# +# Example: +# +# # ---------------------------------------- +# # :section: My Section +# # This is the section that I wrote. +# # See it glisten in the noon-day sun. +# # ---------------------------------------- +# +# ## +# # Comment for some_method +# def some_method +# # ... +# end +# +# You can use directive :category: to temporarily +# override the current section. +# +# - # :category: _section_title_: +# +# - Appears on a line by itself. +# - Specifies that just one following method is to be included +# in the given section, or in the default section if no title is given. +# Subsequent methods are to be grouped into the current section. +# +# ===== Directive for Including a File +# +# - # :include: _filepath_: +# +# - Appears on a line by itself. +# - Specifies that the contents of the given file +# are to be included at this point. +# The file content is shifted to have the same indentation as the colon +# at the start of the directive. +# +# The file is searched for in the directories +# given with the --include command-line option, +# or by default in the current directory. +# +# For C code, the directive may appear in a stand-alone comment +# +# === Text Markup +# +# Text in a paragraph, list item (any type), or heading +# may have markup formatting. +# +# ==== Italic +# +# A single word may be italicized by prefixed and suffixed underscores. +# +# Examples: +# +# # _Word_ in paragraph. +# # - _Word_ in bullet list item. +# # 1. _Word_ in numbered list item. +# # a. _Word_ in lettered list item. +# # [_word_] _Word_ in labeled list item. +# # ====== _Word_ in heading +# +# Any text may be italicized via HTML tag +i+ or +em+. +# +# Examples: +# +# # Two words in paragraph. +# # - Two words in bullet list item. +# # 1. Two words in numbered list item. +# # a. Two words in lettered list item. +# # [Two words] Two words in labeled list item. +# # ====== Two words in heading +# +# ==== Bold +# +# A single word may be made bold by prefixed and suffixed asterisks. +# +# Examples: +# +# # *Word* in paragraph. +# # - *Word* in bullet list item. +# # 1. *Word* in numbered list item. +# # a. *Word* in lettered list item. +# # [*word*] *Word* in labeled list item. +# # ====== *Word* in heading +# +# Any text may be made bold via HTML tag +b+. +# +# Examples: +# +# # Two words in paragraph. +# # - Two words in bullet list item. +# # 1. Two words in numbered list item. +# # a. Two words in lettered list item. +# # [Two words] Two words in labeled list item. +# # ====== Two words in heading +# +# ==== Monofont +# +# A single word may be made monofont -- sometimes called "typewriter font" -- +# by prefixed and suffixed plus-signs. +# +# Examples: +# +# # +Word+ in paragraph. +# # - +Word+ in bullet list item. +# # 1. +Word+ in numbered list item. +# # a. +Word+ in lettered list item. +# # [+word+] +Word+ in labeled list item. +# # ====== +Word+ in heading +# +# Any text may be made monofont via HTML tag +tt+ or +code+. +# +# Examples: +# +# # Two words in paragraph. +# # - Two words in bullet list item. +# # 1. Two words in numbered list item. +# # a. Two words in lettered list item. +# # [Two words] Two words in labeled list item. +# # ====== Two words in heading +# +# ==== Character Conversions +# +# Certain combinations of characters may be converted to special characters; +# whether the conversion occurs depends on whether the special character +# is available in the current encoding. +# +# - (c) converts to (c) (copyright character); must be lowercase. +# +# - (r) converts to (r) (registered trademark character); must be lowercase. +# +# - 'foo' converts to 'foo' (smart single-quotes). +# +# - "foo" converts to "foo" (smart double-quotes). +# +# - foo ... bar converts to foo ... bar (1-character ellipsis). +# +# - foo -- bar converts to foo -- bar (1-character en-dash). +# +# - foo --- bar converts to foo --- bar (1-character em-dash). +# +# ==== Links +# +# Certain strings in \RDoc text are converted to links. +# Any such link may be suppressed by prefixing a backslash. +# This section shows how to link to various +# targets. +# +# [Class] +# +# - On-page: DummyClass links to DummyClass. +# - Off-page: RDoc::Alias links to RDoc::Alias. +# +# [Module] +# +# - On-page: DummyModule links to DummyModule. +# - Off-page: RDoc links to RDoc. +# +# [Constant] +# +# - On-page: DUMMY_CONSTANT links to DUMMY_CONSTANT. +# - Off-page: RDoc::Text::MARKUP_FORMAT links to RDoc::Text::MARKUP_FORMAT. +# +# [Singleton Method] +# +# - On-page: ::dummy_singleton_method links to ::dummy_singleton_method. +# - Off-pageRDoc::TokenStream::to_html links to RDoc::TokenStream::to_html. +# to \RDoc::TokenStream::to_html. +# +# Note: Occasionally \RDoc is not linked to a method whose name +# has only special characters. Check whether the links you were expecting +# are actually there. If not, you'll need to put in an explicit link; +# see below. +# +# Pro tip: The link to any method is available in the alphabetical table of contents +# at the top left of the page for the class or module. +# +# [Instance Method] +# +# - On-page: #dummy_instance_method links to #dummy_instance_method. +# - Off-page: RDoc::Alias#html_name links to RDoc::Alias#html_name. +# +# See the Note and Pro Tip immediately above. +# +# [Attribute] +# +# - On-page: #dummy_attribute links to #dummy_attribute. +# - Off-page: RDoc::Alias#name links to RDoc::Alias#name. +# +# [Alias] +# +# - On-page: #dummy_instance_alias links to #dummy_instance_alias. +# - Off-page: RDoc::Alias#new_name links to RDoc::Alias#new_name. +# +# [Protocol +http+] +# +# - Linked: http://yahoo.com links to http://yahoo.com. +# +# [Protocol +https+] +# +# - Linked: https://github.com links to https://github.com. +# +# [Protocol +www+] +# +# - Linked: www.yahoo.com links to www.yahoo.com. +# +# [Protocol +ftp+] +# +# - Linked: ftp://nosuch.site links to ftp://nosuch.site. +# +# [Protocol +mailto+] +# +# - Linked: mailto:/foo@bar.com links to mailto://foo@bar.com. +# +# [Protocol +irc+] +# +# - link: irc://irc.freenode.net/ruby links to irc://irc.freenode.net/ruby. +# +# [Image Filename Extensions] +# +# - Link: https://www.ruby-lang.org/images/header-ruby-logo@2x.png is +# converted to an in-line HTML +img+ tag, which displays the image in the HTML: +# +# https://www.ruby-lang.org/images/header-ruby-logo@2x.png +# +# Also works for +bmp+, +gif+, +jpeg+, and +jpg+ files. +# +# Note: Works only for a fully qualified URL. +# +# [Heading] +# +# - Link: RDoc::RD@LICENSE links to RDoc::RDoc::RD@LICENSE. +# +# Note that spaces in the actual heading are represented by + characters +# in the linkable text. +# +# - Link: RDoc::Options@Saved+Options +# links to RDoc::Options@Saved+Options. +# +# Punctuation and other special characters must be escaped like CGI.escape. +# +# Pro tip: The link to any heading is available in the alphabetical table of contents +# at the top left of the page for the class or module. +# +# [Section] +# +# See {Directives for Organizing Documentation}[#class-RDoc::MarkupReference-label-Directives+for+Organizing+Documentation]. +# +# - Link: RDoc::Markup::ToHtml@Visitor links to RDoc::Markup::ToHtml@Visitor. +# +# If a section and a heading share the same name, the link target is the section. +# +# [Single-Word Text Link] +# +# Use square brackets to create single-word text link: +# +# - GitHub[https://github.com] links to GitHub[https://github.com]. +# +# [Multi-Word Text Link] +# +# Use square brackets and curly braces to create a multi-word text link. +# +# - {GitHub home page}[https://github.com] links to +# {GitHub home page}[https://github.com]. +# +# [rdoc-ref Scheme] +# +# A link with the rdoc-ref: scheme links to the referenced item, +# if that item exists. +# The referenced item may be a class, module, method, file, etc. +# +# - Class: Alias[rdoc-ref:RDoc::Alias] links to Alias[rdoc-ref:RDoc::Alias]. +# - Module: RDoc[rdoc-ref:RDoc] links to RDoc[rdoc-ref:RDoc]. +# - Method: foo[rdoc-ref:RDoc::Markup::ToHtml#handle_regexp_RDOCLINK] +# links to foo[rdoc-ref:RDoc::Markup::ToHtml#handle_regexp_RDOCLINK]. +# - Constant: bar[rdoc-ref:RDoc::Markup::ToHtml::LIST_TYPE_TO_HTML] +# links to bar[rdoc-ref:RDoc::Markup::ToHtml::LIST_TYPE_TO_HTML]. +# - Attribute: baz[rdoc-ref:RDoc::Markup::ToHtml#code_object] +# links to baz[rdoc-ref:RDoc::Markup::ToHtml#code_object]. +# - Alias: bad[rdoc-ref:RDoc::MarkupReference#dummy_instance_alias] links to +# bad[rdoc-ref:RDoc::MarkupReference#dummy_instance_alias]. +# +# If the referenced item does not exist, no link is generated +# and entire rdoc-ref: square-bracketed clause is removed +# from the resulting text. +# +# - Nosuch[rdoc-ref:RDoc::Nosuch] is rendered as +# Nosuch[rdoc-ref:RDoc::Nosuch]. +# +# +# [rdoc-label Scheme] +# +# [Simple] +# +# You can specify a link target using this form, +# where the second part cites the id of an HTML element. +# +# This link refers to the constant +DUMMY_CONSTANT+ on this page: +# +# - {DUMMY_CONSTANT}[rdoc-label:DUMMY_CONSTANT] +# +# Thus: +# +# {DUMMY_CONSTANT}[rdoc-label:DUMMY_CONSTANT] +# +# [With Return] +# +# You can specify both a link target and a local label +# that can be used as the target for a return link. +# These two links refer to each other: +# +# - {go to addressee}[rdoc-label:addressee:sender] +# - {return to sender}[rdoc-label:sender:addressee] +# +# Thus: +# +# {go to addressee}[rdoc-label:addressee:sender] +# +# Some text. +# +# {return to sender}[rdoc-label:sender:addressee] +# +# [link: Scheme] +# +# - link:README_rdoc.html links to link:README_rdoc.html. +# +# [rdoc-image Scheme] +# +# Use the rdoc-image scheme to display an image that is also a link: +# +# # {rdoc-image:path/to/image}[link_target] +# +# - Link: {rdoc-image:https://www.ruby-lang.org/images/header-ruby-logo@2x.png}[https://www.ruby-lang.org] +# displays image https://www.ruby-lang.org/images/header-ruby-logo@2x.png +# as a link to https://www.ruby-lang.org. +# +# {rdoc-image:https://www.ruby-lang.org/images/header-ruby-logo@2x.png}[https://www.ruby-lang.org] +# +# A relative path as the target also works: +# +# - Link: {rdoc-image:https://www.ruby-lang.org/images/header-ruby-logo@2x.png}[./Alias.html] links to ./Alias.html +# +# {rdoc-image:https://www.ruby-lang.org/images/header-ruby-logo@2x.png}[./Alias.html] +# +# == Documentation Derived from Ruby Code +# +# [Class] +# +# By default, \RDoc documents: +# +# - \Class name. +# - Parent class. +# - Singleton methods. +# - Instance methods. +# - Aliases. +# - Constants. +# - Attributes. +# +# [Module] +# +# By default, \RDoc documents: +# +# - \Module name. +# - \Singleton methods. +# - Instance methods. +# - Aliases. +# - Constants. +# - Attributes. +# +# [Method] +# +# By default, \RDoc documents: +# +# - \Method name. +# - Arguments. +# - Yielded values. +# +# See #method. +# +# [Alias] +# +# By default, \RDoc documents: +# +# - Alias name. +# - Aliased name. +# +# See #dummy_instance_alias and #dummy_instance_method. +# +# [Constant] +# +# By default, \RDoc documents: +# +# - \Constant name. +# +# See DUMMY_CONSTANT. +# +# [Attribute] +# +# By default, \RDoc documents: +# +# - Attribute name. +# - Attribute type ([R], [W], or [RW]) +# +# See #dummy_attribute. +# +class RDoc::MarkupReference + + class DummyClass; end + module DummyModule; end + def self.dummy_singleton_method(foo, bar); end + def dummy_instance_method(foo, bar); end; + alias dummy_instance_alias dummy_instance_method + attr_accessor :dummy_attribute + alias dummy_attribute_alias dummy_attribute + DUMMY_CONSTANT = '' + + # :call-seq: + # call_seq_directive(foo, bar) + # Can be anything -> bar + # Also anything more -> baz or bat + # + # The :call-seq: directive overrides the actual calling sequence + # found in the Ruby code. + # + # - It can specify anything at all. + # - It can have multiple calling sequences. + # + # This one includes Can be anything -> foo, which is nonsense. + # + # Note that the "arrow" is two characters, hyphen and right angle-bracket, + # which is made into a single character in the HTML. + # + # Click on the calling sequence to see the code. + # + # Here is the :call-seq: directive given for the method: + # + # # :call-seq: + # # call_seq_directive(foo, bar) + # # Can be anything -> bar + # # Also anything more -> baz or bat + # + def call_seq_directive + nil + end + + # The :args: directive overrides the actual arguments found in the Ruby code. + # + # Click on the calling sequence to see the code. + # + def args_directive(foo, bar) # :args: baz + nil + end + + # The :yields: directive overrides the actual yield found in the Ruby code. + # + # Click on the calling sequence to see the code. + # + def yields_directive(foo, bar) # :yields: 'bat' + yield 'baz' + end + + # This method is documented only by \RDoc, except for these comments. + # + # Click on the calling sequence to see the code. + # + def method(foo, bar) + yield 'baz' + end + +end diff --git a/enc/Makefile.in b/enc/Makefile.in index 5e5d39cd76498d..dd8ca1b5281aad 100644 --- a/enc/Makefile.in +++ b/enc/Makefile.in @@ -22,6 +22,7 @@ TRANSSODIR = $(ENCSODIR)/trans DLEXT = @DLEXT@ OBJEXT = @OBJEXT@ LIBEXT = @LIBEXT@ +EXEEXT = @EXEEXT@ TIMESTAMPDIR = $(EXTOUT)/.timestamp ENC_TRANS_D = $(TIMESTAMPDIR)/.enc-trans.time ENC_TRANS_SO_D = $(TIMESTAMPDIR)/.enc-trans.so.time @@ -35,6 +36,7 @@ RUBY_SO_NAME = @RUBY_SO_NAME@ LIBRUBY = @LIBRUBY@ LIBRUBYARG_SHARED = @LIBRUBYARG_SHARED@ LIBRUBYARG_STATIC = $(LIBRUBYARG_SHARED) +BUILTRUBY = $(topdir)/miniruby$(EXEEXT) empty = AR = @AR@ diff --git a/enum.c b/enum.c index 6b69fef8a1453f..e3dc177ba17729 100644 --- a/enum.c +++ b/enum.c @@ -1487,7 +1487,7 @@ enum_sort_by(VALUE obj) ary = rb_ary_new(); } RBASIC_CLEAR_CLASS(ary); - buf = rb_ary_tmp_new(SORT_BY_BUFSIZE*2); + buf = rb_ary_hidden_new(SORT_BY_BUFSIZE*2); rb_ary_store(buf, SORT_BY_BUFSIZE*2-1, Qnil); memo = MEMO_NEW(0, 0, 0); data = (struct sort_by_data *)&memo->v1; @@ -1863,7 +1863,7 @@ rb_nmin_run(VALUE obj, VALUE num, int by, int rev, int ary) rb_raise(rb_eArgError, "too big size"); data.bufmax = data.n * 4; data.curlen = 0; - data.buf = rb_ary_tmp_new(data.bufmax * (by ? 2 : 1)); + data.buf = rb_ary_hidden_new(data.bufmax * (by ? 2 : 1)); data.limit = Qundef; data.cmpfunc = by ? nmin_cmp : rb_block_given_p() ? nmin_block_cmp : diff --git a/enumerator.c b/enumerator.c index 89abf4b8881da7..ce2eacbd2a8d8a 100644 --- a/enumerator.c +++ b/enumerator.c @@ -125,7 +125,7 @@ */ VALUE rb_cEnumerator; static VALUE rb_cLazy; -static ID id_rewind, id_new, id_to_enum; +static ID id_rewind, id_new, id_to_enum, id_each_entry; static ID id_next, id_result, id_receiver, id_arguments, id_memo, id_method, id_force; static ID id_begin, id_end, id_step, id_exclude_end; static VALUE sym_each, sym_cycle, sym_yield; @@ -194,6 +194,12 @@ struct enum_chain { long pos; }; +static VALUE rb_cEnumProduct; + +struct enum_product { + VALUE enums; +}; + VALUE rb_cArithSeq; /* @@ -3347,6 +3353,335 @@ enumerator_plus(VALUE obj, VALUE eobj) return new_enum_chain(rb_ary_new_from_args(2, obj, eobj)); } +/* + * Document-class: Enumerator::Product + * + * Enumerator::Product generates a Cartesian product of any number of + * enumerable objects. Iterating over the product of enumerable + * objects is roughly equivalent to nested each_entry loops where the + * loop for the rightmost object is put innermost. + * + * innings = Enumerator::Product.new(1..9, ['top', 'bottom']) + * + * innings.each do |i, h| + * p [i, h] + * end + * # [1, "top"] + * # [1, "bottom"] + * # [2, "top"] + * # [2, "bottom"] + * # [3, "top"] + * # [3, "bottom"] + * # ... + * # [9, "top"] + * # [9, "bottom"] + * + * The method used against each enumerable object is `each_entry` + * instead of `each` so that the product of N enumerable objects + * yields exactly N arguments in each iteration. + * + * When no enumerator is given, it calls a given block once yielding + * an empty argument list. + * + * This type of objects can be created by Enumerator.product. + */ + +static void +enum_product_mark(void *p) +{ + struct enum_product *ptr = p; + rb_gc_mark_movable(ptr->enums); +} + +static void +enum_product_compact(void *p) +{ + struct enum_product *ptr = p; + ptr->enums = rb_gc_location(ptr->enums); +} + +#define enum_product_free RUBY_TYPED_DEFAULT_FREE + +static size_t +enum_product_memsize(const void *p) +{ + return sizeof(struct enum_product); +} + +static const rb_data_type_t enum_product_data_type = { + "product", + { + enum_product_mark, + enum_product_free, + enum_product_memsize, + enum_product_compact, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY +}; + +static struct enum_product * +enum_product_ptr(VALUE obj) +{ + struct enum_product *ptr; + + TypedData_Get_Struct(obj, struct enum_product, &enum_product_data_type, ptr); + if (!ptr || ptr->enums == Qundef) { + rb_raise(rb_eArgError, "uninitialized product"); + } + return ptr; +} + +/* :nodoc: */ +static VALUE +enum_product_allocate(VALUE klass) +{ + struct enum_product *ptr; + VALUE obj; + + obj = TypedData_Make_Struct(klass, struct enum_product, &enum_product_data_type, ptr); + ptr->enums = Qundef; + + return obj; +} + +/* + * call-seq: + * Enumerator::Product.new(*enums) -> enum + * + * Generates a new enumerator object that generates a Cartesian + * product of given enumerable objects. + * + * e = Enumerator::Product.new(1..3, [4, 5]) + * e.to_a #=> [[1, 4], [1, 5], [2, 4], [2, 5], [3, 4], [3, 5]] + * e.size #=> 6 + */ +static VALUE +enum_product_initialize(VALUE obj, VALUE enums) +{ + struct enum_product *ptr; + + rb_check_frozen(obj); + TypedData_Get_Struct(obj, struct enum_product, &enum_product_data_type, ptr); + + if (!ptr) rb_raise(rb_eArgError, "unallocated product"); + + ptr->enums = rb_obj_freeze(enums); + + return obj; +} + +/* :nodoc: */ +static VALUE +enum_product_init_copy(VALUE obj, VALUE orig) +{ + struct enum_product *ptr0, *ptr1; + + if (!OBJ_INIT_COPY(obj, orig)) return obj; + ptr0 = enum_product_ptr(orig); + + TypedData_Get_Struct(obj, struct enum_product, &enum_product_data_type, ptr1); + + if (!ptr1) rb_raise(rb_eArgError, "unallocated product"); + + ptr1->enums = ptr0->enums; + + return obj; +} + +static VALUE +enum_product_total_size(VALUE enums) +{ + VALUE total = INT2FIX(1); + long i; + + for (i = 0; i < RARRAY_LEN(enums); i++) { + VALUE size = enum_size(RARRAY_AREF(enums, i)); + + if (NIL_P(size) || (RB_TYPE_P(size, T_FLOAT) && isinf(NUM2DBL(size)))) { + return size; + } + if (!RB_INTEGER_TYPE_P(size)) { + return Qnil; + } + + total = rb_funcall(total, '*', 1, size); + } + + return total; +} + +/* + * call-seq: + * obj.size -> int, Float::INFINITY or nil + * + * Returns the total size of the enumerator product calculated by + * multiplying the sizes of enumerables in the product. If any of the + * enumerables reports its size as nil or Float::INFINITY, that value + * is returned as the size. + */ +static VALUE +enum_product_size(VALUE obj) +{ + return enum_product_total_size(enum_product_ptr(obj)->enums); +} + +static VALUE +enum_product_enum_size(VALUE obj, VALUE args, VALUE eobj) +{ + return enum_product_size(obj); +} + +struct product_state { + VALUE obj; + VALUE block; + int argc; + VALUE *argv; + int index; +}; + +static VALUE product_each(VALUE, struct product_state *); + +static VALUE +product_each_i(RB_BLOCK_CALL_FUNC_ARGLIST(value, state)) +{ + struct product_state *pstate = (struct product_state *)state; + pstate->argv[pstate->index++] = value; + + VALUE val = product_each(pstate->obj, pstate); + pstate->index--; + return val; +} + +static VALUE +product_each(VALUE obj, struct product_state *pstate) +{ + struct enum_product *ptr = enum_product_ptr(obj); + VALUE enums = ptr->enums; + + if (pstate->index < pstate->argc) { + VALUE eobj = RARRAY_AREF(enums, pstate->index); + + rb_block_call(eobj, id_each_entry, 0, NULL, product_each_i, (VALUE)pstate); + } else { + rb_funcallv(pstate->block, id_call, pstate->argc, pstate->argv); + } + + return obj; +} + +static VALUE +enum_product_run(VALUE obj, VALUE block) +{ + struct enum_product *ptr = enum_product_ptr(obj); + int argc = RARRAY_LENINT(ptr->enums); + struct product_state state = { + .obj = obj, + .block = block, + .index = 0, + .argc = argc, + .argv = ALLOCA_N(VALUE, argc), + }; + + return product_each(obj, &state); +} + +/* + * call-seq: + * obj.each { |...| ... } -> obj + * obj.each -> enumerator + * + * Iterates over the elements of the first enumerable by calling the + * "each_entry" method on it with the given arguments, then proceeds + * to the following enumerables in sequence until all of the + * enumerables are exhausted. + * + * If no block is given, returns an enumerator. Otherwise, returns self. + */ +static VALUE +enum_product_each(VALUE obj) +{ + RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_product_enum_size); + + return enum_product_run(obj, rb_block_proc()); +} + +/* + * call-seq: + * obj.rewind -> obj + * + * Rewinds the product enumerator by calling the "rewind" method on + * each enumerable in reverse order. Each call is performed only if + * the enumerable responds to the method. + */ +static VALUE +enum_product_rewind(VALUE obj) +{ + struct enum_product *ptr = enum_product_ptr(obj); + VALUE enums = ptr->enums; + long i; + + for (i = 0; i < RARRAY_LEN(enums); i++) { + rb_check_funcall(RARRAY_AREF(enums, i), id_rewind, 0, 0); + } + + return obj; +} + +static VALUE +inspect_enum_product(VALUE obj, VALUE dummy, int recur) +{ + VALUE klass = rb_obj_class(obj); + struct enum_product *ptr; + + TypedData_Get_Struct(obj, struct enum_product, &enum_product_data_type, ptr); + + if (!ptr || ptr->enums == Qundef) { + return rb_sprintf("#<%"PRIsVALUE": uninitialized>", rb_class_path(klass)); + } + + if (recur) { + return rb_sprintf("#<%"PRIsVALUE": ...>", rb_class_path(klass)); + } + + return rb_sprintf("#<%"PRIsVALUE": %+"PRIsVALUE">", rb_class_path(klass), ptr->enums); +} + +/* + * call-seq: + * obj.inspect -> string + * + * Returns a printable version of the product enumerator. + */ +static VALUE +enum_product_inspect(VALUE obj) +{ + return rb_exec_recursive(inspect_enum_product, obj, 0); +} + +/* + * call-seq: + * Enumerator.product(*enums) -> enumerator + * + * Generates a new enumerator object that generates a Cartesian + * product of given enumerable objects. This is equivalent to + * Enumerator::Product.new. + * + * e = Enumerator.product(1..3, [4, 5]) + * e.to_a #=> [[1, 4], [1, 5], [2, 4], [2, 5], [3, 4], [3, 5]] + * e.size #=> 6 + */ +static VALUE +enumerator_s_product(VALUE klass, VALUE enums) +{ + VALUE obj = enum_product_initialize(enum_product_allocate(rb_cEnumProduct), enums); + + if (rb_block_given_p()) { + return enum_product_run(obj, rb_block_proc()); + } else { + return obj; + } +} + /* * Document-class: Enumerator::ArithmeticSequence * @@ -4214,6 +4549,22 @@ InitVM_Enumerator(void) rb_undef_method(rb_cEnumChain, "peek"); rb_undef_method(rb_cEnumChain, "peek_values"); + /* Product */ + rb_cEnumProduct = rb_define_class_under(rb_cEnumerator, "Product", rb_cEnumerator); + rb_define_alloc_func(rb_cEnumProduct, enum_product_allocate); + rb_define_method(rb_cEnumProduct, "initialize", enum_product_initialize, -2); + rb_define_method(rb_cEnumProduct, "initialize_copy", enum_product_init_copy, 1); + rb_define_method(rb_cEnumProduct, "each", enum_product_each, 0); + rb_define_method(rb_cEnumProduct, "size", enum_product_size, 0); + rb_define_method(rb_cEnumProduct, "rewind", enum_product_rewind, 0); + rb_define_method(rb_cEnumProduct, "inspect", enum_product_inspect, 0); + rb_undef_method(rb_cEnumProduct, "feed"); + rb_undef_method(rb_cEnumProduct, "next"); + rb_undef_method(rb_cEnumProduct, "next_values"); + rb_undef_method(rb_cEnumProduct, "peek"); + rb_undef_method(rb_cEnumProduct, "peek_values"); + rb_define_singleton_method(rb_cEnumerator, "product", enumerator_s_product, -2); + /* ArithmeticSequence */ rb_cArithSeq = rb_define_class_under(rb_cEnumerator, "ArithmeticSequence", rb_cEnumerator); rb_undef_alloc_func(rb_cArithSeq); @@ -4249,6 +4600,7 @@ Init_Enumerator(void) id_method = rb_intern_const("method"); id_force = rb_intern_const("force"); id_to_enum = rb_intern_const("to_enum"); + id_each_entry = rb_intern_const("each_entry"); id_begin = rb_intern_const("begin"); id_end = rb_intern_const("end"); id_step = rb_intern_const("step"); diff --git a/ext/-test-/debug/profile_frames.c b/ext/-test-/debug/profile_frames.c index 5f14755ce755d1..d2bba7d1834e1b 100644 --- a/ext/-test-/debug/profile_frames.c +++ b/ext/-test-/debug/profile_frames.c @@ -29,6 +29,7 @@ profile_frames(VALUE self, VALUE start_v, VALUE num_v) rb_ary_push(ary, rb_profile_frame_singleton_method_p(buff[i])); rb_ary_push(ary, rb_profile_frame_method_name(buff[i])); rb_ary_push(ary, rb_profile_frame_qualified_method_name(buff[i])); + rb_ary_push(ary, INT2NUM(lines[i])); rb_ary_push(result, ary); } diff --git a/ext/-test-/enumerator_kw/enumerator_kw.c b/ext/-test-/enumerator_kw/enumerator_kw.c index 947d2b37e624ad..9104c518694634 100644 --- a/ext/-test-/enumerator_kw/enumerator_kw.c +++ b/ext/-test-/enumerator_kw/enumerator_kw.c @@ -14,7 +14,8 @@ enumerator_kw(int argc, VALUE *argv, VALUE self) } void -Init_enumerator_kw(void) { +Init_enumerator_kw(void) +{ VALUE module = rb_define_module("Bug"); module = rb_define_module_under(module, "EnumeratorKw"); rb_define_method(module, "m", enumerator_kw, -1); diff --git a/ext/-test-/eval/eval.c b/ext/-test-/eval/eval.c new file mode 100644 index 00000000000000..983468fc347c7d --- /dev/null +++ b/ext/-test-/eval/eval.c @@ -0,0 +1,13 @@ +#include "ruby/ruby.h" + +static VALUE +eval_string(VALUE self, VALUE str) +{ + return rb_eval_string(StringValueCStr(str)); +} + +void +Init_eval(void) +{ + rb_define_global_function("rb_eval_string", eval_string, 1); +} diff --git a/ext/-test-/eval/extconf.rb b/ext/-test-/eval/extconf.rb new file mode 100644 index 00000000000000..cdbf6a8597fccf --- /dev/null +++ b/ext/-test-/eval/extconf.rb @@ -0,0 +1,2 @@ +require 'mkmf' +create_makefile('-test-/eval') diff --git a/ext/-test-/rb_call_super_kw/rb_call_super_kw.c b/ext/-test-/rb_call_super_kw/rb_call_super_kw.c index 7f094545d29150..61681ed7334498 100644 --- a/ext/-test-/rb_call_super_kw/rb_call_super_kw.c +++ b/ext/-test-/rb_call_super_kw/rb_call_super_kw.c @@ -7,7 +7,8 @@ rb_call_super_kw_m(int argc, VALUE *argv, VALUE self) } void -Init_rb_call_super_kw(void) { +Init_rb_call_super_kw(void) +{ VALUE module = rb_define_module("Bug"); module = rb_define_module_under(module, "RbCallSuperKw"); rb_define_method(module, "m", rb_call_super_kw_m, -1); diff --git a/ext/bigdecimal/bigdecimal.gemspec b/ext/bigdecimal/bigdecimal.gemspec index 2ed7d09373b03c..1feed332f66f6e 100644 --- a/ext/bigdecimal/bigdecimal.gemspec +++ b/ext/bigdecimal/bigdecimal.gemspec @@ -9,7 +9,7 @@ Gem::Specification.new do |s| s.summary = "Arbitrary-precision decimal floating-point number library." s.description = "This library provides arbitrary-precision decimal floating-point number class." s.homepage = "https://github.com/ruby/bigdecimal" - s.license = "Ruby" + s.licenses = ["Ruby", "bsd-2-clause"] s.require_paths = %w[lib] s.extensions = %w[ext/bigdecimal/extconf.rb] diff --git a/ext/date/date.gemspec b/ext/date/date.gemspec index cf076969766788..eecbf786a38195 100644 --- a/ext/date/date.gemspec +++ b/ext/date/date.gemspec @@ -12,6 +12,7 @@ Gem::Specification.new do |s| s.require_path = %w{lib} s.files = [ + "README.md", "lib/date.rb", "ext/date/date_core.c", "ext/date/date_parse.c", "ext/date/date_strftime.c", "ext/date/date_strptime.c", "ext/date/date_tmx.h", "ext/date/extconf.rb", "ext/date/prereq.mk", "ext/date/zonetab.h", "ext/date/zonetab.list" diff --git a/ext/date/date_core.c b/ext/date/date_core.c index d7ebcaa784a99b..cee7b27faf6d08 100644 --- a/ext/date/date_core.c +++ b/ext/date/date_core.c @@ -465,6 +465,7 @@ c_find_ldoy(int y, double sg, int *rjd, int *ns) } #ifndef NDEBUG +/* :nodoc: */ static int c_find_fdom(int y, int m, double sg, int *rjd, int *ns) { @@ -621,6 +622,7 @@ c_jd_to_weeknum(int jd, int f, double sg, int *ry, int *rw, int *rd) } #ifndef NDEBUG +/* :nodoc: */ static void c_nth_kday_to_jd(int y, int m, int n, int k, double sg, int *rjd, int *ns) { @@ -646,6 +648,7 @@ c_jd_to_wday(int jd) } #ifndef NDEBUG +/* :nodoc: */ static void c_jd_to_nth_kday(int jd, double sg, int *ry, int *rm, int *rn, int *rk) { @@ -822,6 +825,7 @@ c_valid_weeknum_p(int y, int w, int d, int f, double sg, } #ifndef NDEBUG +/* :nodoc: */ static int c_valid_nth_kday_p(int y, int m, int n, int k, double sg, int *rm, int *rn, int *rk, int *rjd, int *ns) @@ -963,6 +967,7 @@ ns_to_day(VALUE n) } #ifndef NDEBUG +/* :nodoc: */ static VALUE ms_to_sec(VALUE m) { @@ -981,6 +986,7 @@ ns_to_sec(VALUE n) } #ifndef NDEBUG +/* :nodoc: */ inline static VALUE ins_to_day(int n) { @@ -1016,6 +1022,7 @@ day_to_sec(VALUE d) } #ifndef NDEBUG +/* :nodoc: */ static VALUE day_to_ns(VALUE d) { @@ -1040,6 +1047,7 @@ sec_to_ns(VALUE s) } #ifndef NDEBUG +/* :nodoc: */ static VALUE isec_to_ns(int s) { @@ -1066,6 +1074,7 @@ div_df(VALUE d, VALUE *f) } #ifndef NDEBUG +/* :nodoc: */ static VALUE div_sf(VALUE s, VALUE *f) { @@ -1500,6 +1509,7 @@ m_df(union DateData *x) } #ifndef NDEBUG +/* :nodoc: */ static VALUE m_df_in_day(union DateData *x) { @@ -1997,6 +2007,7 @@ expect_numeric(VALUE x) } #ifndef NDEBUG +/* :nodoc: */ static void civil_to_jd(VALUE y, int m, int d, double sg, VALUE *nth, int *ry, @@ -2309,6 +2320,7 @@ valid_weeknum_p(VALUE y, int w, int d, int f, double sg, } #ifndef NDEBUG +/* :nodoc: */ static int valid_nth_kday_p(VALUE y, int m, int n, int k, double sg, VALUE *nth, int *ry, @@ -2446,6 +2458,7 @@ valid_jd_sub(int argc, VALUE *argv, VALUE klass, int need_jd) } #ifndef NDEBUG +/* :nodoc: */ static VALUE date_s__valid_jd_p(int argc, VALUE *argv, VALUE klass) { @@ -2535,6 +2548,7 @@ valid_civil_sub(int argc, VALUE *argv, VALUE klass, int need_jd) } #ifndef NDEBUG +/* :nodoc: */ static VALUE date_s__valid_civil_p(int argc, VALUE *argv, VALUE klass) { @@ -2626,6 +2640,7 @@ valid_ordinal_sub(int argc, VALUE *argv, VALUE klass, int need_jd) } #ifndef NDEBUG +/* :nodoc: */ static VALUE date_s__valid_ordinal_p(int argc, VALUE *argv, VALUE klass) { @@ -2712,6 +2727,7 @@ valid_commercial_sub(int argc, VALUE *argv, VALUE klass, int need_jd) } #ifndef NDEBUG +/* :nodoc: */ static VALUE date_s__valid_commercial_p(int argc, VALUE *argv, VALUE klass) { @@ -2773,6 +2789,7 @@ date_s_valid_commercial_p(int argc, VALUE *argv, VALUE klass) } #ifndef NDEBUG +/* :nodoc: */ static VALUE valid_weeknum_sub(int argc, VALUE *argv, VALUE klass, int need_jd) { @@ -2804,6 +2821,7 @@ valid_weeknum_sub(int argc, VALUE *argv, VALUE klass, int need_jd) } } +/* :nodoc: */ static VALUE date_s__valid_weeknum_p(int argc, VALUE *argv, VALUE klass) { @@ -2824,6 +2842,7 @@ date_s__valid_weeknum_p(int argc, VALUE *argv, VALUE klass) return valid_weeknum_sub(5, argv2, klass, 1); } +/* :nodoc: */ static VALUE date_s_valid_weeknum_p(int argc, VALUE *argv, VALUE klass) { @@ -2875,6 +2894,7 @@ valid_nth_kday_sub(int argc, VALUE *argv, VALUE klass, int need_jd) } } +/* :nodoc: */ static VALUE date_s__valid_nth_kday_p(int argc, VALUE *argv, VALUE klass) { @@ -2895,6 +2915,7 @@ date_s__valid_nth_kday_p(int argc, VALUE *argv, VALUE klass) return valid_nth_kday_sub(5, argv2, klass, 1); } +/* :nodoc: */ static VALUE date_s_valid_nth_kday_p(int argc, VALUE *argv, VALUE klass) { @@ -2917,6 +2938,7 @@ date_s_valid_nth_kday_p(int argc, VALUE *argv, VALUE klass) return Qtrue; } +/* :nodoc: */ static VALUE date_s_zone_to_diff(VALUE klass, VALUE str) { @@ -3112,6 +3134,7 @@ old_to_new(VALUE ajd, VALUE of, VALUE sg, } #ifndef NDEBUG +/* :nodoc: */ static VALUE date_s_new_bang(int argc, VALUE *argv, VALUE klass) { @@ -3623,6 +3646,7 @@ date_s_commercial(int argc, VALUE *argv, VALUE klass) } #ifndef NDEBUG +/* :nodoc: */ static VALUE date_s_weeknum(int argc, VALUE *argv, VALUE klass) { @@ -3672,6 +3696,7 @@ date_s_weeknum(int argc, VALUE *argv, VALUE klass) return ret; } +/* :nodoc: */ static VALUE date_s_nth_kday(int argc, VALUE *argv, VALUE klass) { @@ -4346,14 +4371,18 @@ date_s__strptime_internal(int argc, VALUE *argv, VALUE klass, * call-seq: * Date._strptime(string, format = '%F') -> hash * - * Parses the given representation of date and time with the given - * template, and returns a hash of parsed elements. _strptime does - * not support specification of flags and width unlike strftime. + * Returns a hash of values parsed from +string+ + * according to the given +format+: * - * Date._strptime('2001-02-03', '%Y-%m-%d') - * #=> {:year=>2001, :mon=>2, :mday=>3} + * Date._strptime('2001-02-03', '%Y-%m-%d') # => {:year=>2001, :mon=>2, :mday=>3} * - * See also strptime(3) and #strftime. + * For other formats, see + * {Formats for Dates and Times}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html]. + * (Unlike Date.strftime, does not support flags and width.) + * + * See also {strptime(3)}[https://man7.org/linux/man-pages/man3/strptime.3.html]. + * + * Related: Date.strptime (returns a \Date object). */ static VALUE date_s__strptime(int argc, VALUE *argv, VALUE klass) @@ -4365,21 +4394,26 @@ date_s__strptime(int argc, VALUE *argv, VALUE klass) * call-seq: * Date.strptime(string = '-4712-01-01', format = '%F', start = Date::ITALY) -> date * - * Parses the given representation of date and time with the given - * template, and creates a date object. strptime does not support - * specification of flags and width unlike strftime. + * Returns a new \Date object with values parsed from +string+, + * according to the given +format+: * - * Date.strptime('2001-02-03', '%Y-%m-%d') #=> # - * Date.strptime('03-02-2001', '%d-%m-%Y') #=> # - * Date.strptime('2001-034', '%Y-%j') #=> # - * Date.strptime('2001-W05-6', '%G-W%V-%u') #=> # - * Date.strptime('2001 04 6', '%Y %U %w') #=> # - * Date.strptime('2001 05 6', '%Y %W %u') #=> # - * Date.strptime('sat3feb01', '%a%d%b%y') #=> # + * Date.strptime('2001-02-03', '%Y-%m-%d') # => # + * Date.strptime('03-02-2001', '%d-%m-%Y') # => # + * Date.strptime('2001-034', '%Y-%j') # => # + * Date.strptime('2001-W05-6', '%G-W%V-%u') # => # + * Date.strptime('2001 04 6', '%Y %U %w') # => # + * Date.strptime('2001 05 6', '%Y %W %u') # => # + * Date.strptime('sat3feb01', '%a%d%b%y') # => # + * + * For other formats, see + * {Formats for Dates and Times}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html]. + * (Unlike Date.strftime, does not support flags and width.) * * See argument {start}[rdoc-ref:Date@Argument+start]. * - * See also strptime(3) and #strftime. + * See also {strptime(3)}[https://man7.org/linux/man-pages/man3/strptime.3.html]. + * + * Related: Date._strptime (returns a hash). */ static VALUE date_s_strptime(int argc, VALUE *argv, VALUE klass) @@ -4468,23 +4502,27 @@ date_s__parse_internal(int argc, VALUE *argv, VALUE klass) * call-seq: * Date._parse(string, comp = true, limit: 128) -> hash * - * Parses the given representation of date and time, and returns a - * hash of parsed elements. + * Note: + * This method recognizes many forms in +string+, + * but it is not a validator. + * If +string+ does not specify a valid date, + * the result is unpredictable; + * consider using Date._strptime instead. * - * This method *does not* function as a validator. If the input - * string does not match valid formats strictly, you may get a cryptic - * result. Should consider to use `Date._strptime` or - * `DateTime._strptime` instead of this method as possible. + * Returns a hash of values parsed from +string+: * - * If the optional second argument is true and the detected year is in - * the range "00" to "99", considers the year a 2-digit form and makes - * it full. + * Date._parse('2001-02-03') # => {:year=>2001, :mon=>2, :mday=>3} * - * Date._parse('2001-02-03') #=> {:year=>2001, :mon=>2, :mday=>3} + * If +comp+ is +true+ and the given year is in the range (0..99), + * the current century is supplied; + * otherwise, the year is taken as given: * - * Raise an ArgumentError when the string length is longer than _limit_. - * You can stop this check by passing `limit: nil`, but note that - * it may take a long time to parse. + * Date._parse('01-02-03', true) # => {:year=>2001, :mon=>2, :mday=>3} + * Date._parse('01-02-03', false) # => {:year=>1, :mon=>2, :mday=>3} + * + * See argument {limit}[rdoc-ref:Date@Argument+limit]. + * + * Related: Date.parse(returns a \Date object). */ static VALUE date_s__parse(int argc, VALUE *argv, VALUE klass) @@ -4496,27 +4534,32 @@ date_s__parse(int argc, VALUE *argv, VALUE klass) * call-seq: * Date.parse(string = '-4712-01-01', comp = true, start = Date::ITALY, limit: 128) -> date * - * Parses the given representation of date and time, and creates a - * date object. + * Note: + * This method recognizes many forms in +string+, + * but it is not a validator. + * If +string+ does not specify a valid date, + * the result is unpredictable; + * consider using Date._strptime instead. * - * This method *does not* function as a validator. If the input - * string does not match valid formats strictly, you may get a cryptic - * result. Should consider to use `Date.strptime` instead of this - * method as possible. + * Returns a new \Date object with values parsed from +string+: * - * If the optional second argument is true and the detected year is in - * the range "00" to "99", considers the year a 2-digit form and makes - * it full. + * Date.parse('2001-02-03') # => # + * Date.parse('20010203') # => # + * Date.parse('3rd Feb 2001') # => # * - * Date.parse('2001-02-03') #=> # - * Date.parse('20010203') #=> # - * Date.parse('3rd Feb 2001') #=> # + * If +comp+ is +true+ and the given year is in the range (0..99), + * the current century is supplied; + * otherwise, the year is taken as given: * - * Raise an ArgumentError when the string length is longer than _limit_. - * You can stop this check by passing `limit: nil`, but note that - * it may take a long time to parse. + * Date.parse('01-02-03', true) # => # + * Date.parse('01-02-03', false) # => # * - * See argument {start}[rdoc-ref:Date@Argument+start]. + * See: + * + * - Argument {start}[rdoc-ref:Date@Argument+start]. + * - Argument {limit}[rdoc-ref:Date@Argument+limit]. + * + * Related: Date._parse (returns a hash). */ static VALUE date_s_parse(int argc, VALUE *argv, VALUE klass) @@ -4557,11 +4600,16 @@ VALUE date__jisx0301(VALUE); * call-seq: * Date._iso8601(string, limit: 128) -> hash * - * Returns a hash of parsed elements. + * Returns a hash of values parsed from +string+, which should contain + * an {ISO 8601 formatted date}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html#label-ISO+8601+Format+Specifications]: * - * Raise an ArgumentError when the string length is longer than _limit_. - * You can stop this check by passing `limit: nil`, but note that - * it may take a long time to parse. + * d = Date.new(2001, 2, 3) + * s = d.iso8601 # => "2001-02-03" + * Date._iso8601(s) # => {:mday=>3, :year=>2001, :mon=>2} + * + * See argument {limit}[rdoc-ref:Date@Argument+limit]. + * + * Related: Date.iso8601 (returns a \Date object). */ static VALUE date_s__iso8601(int argc, VALUE *argv, VALUE klass) @@ -4578,18 +4626,20 @@ date_s__iso8601(int argc, VALUE *argv, VALUE klass) * call-seq: * Date.iso8601(string = '-4712-01-01', start = Date::ITALY, limit: 128) -> date * - * Creates a new Date object by parsing from a string according to - * some typical ISO 8601 formats. + * Returns a new \Date object with values parsed from +string+, + * which should contain + * an {ISO 8601 formatted date}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html#label-ISO+8601+Format+Specifications]: * - * Date.iso8601('2001-02-03') #=> # - * Date.iso8601('20010203') #=> # - * Date.iso8601('2001-W05-6') #=> # + * d = Date.new(2001, 2, 3) + * s = d.iso8601 # => "2001-02-03" + * Date.iso8601(s) # => # * - * Raise an ArgumentError when the string length is longer than _limit_. - * You can stop this check by passing `limit: nil`, but note that - * it may take a long time to parse. + * See: * - * See argument {start}[rdoc-ref:Date@Argument+start]. + * - Argument {start}[rdoc-ref:Date@Argument+start]. + * - Argument {limit}[rdoc-ref:Date@Argument+limit]. + * + * Related: Date._iso8601 (returns a hash). */ static VALUE date_s_iso8601(int argc, VALUE *argv, VALUE klass) @@ -4620,11 +4670,17 @@ date_s_iso8601(int argc, VALUE *argv, VALUE klass) * call-seq: * Date._rfc3339(string, limit: 128) -> hash * - * Returns a hash of parsed elements. + * Returns a hash of values parsed from +string+, which should be a valid + * {RFC 3339 format}[https://datatracker.ietf.org/doc/html/rfc3339]: * - * Raise an ArgumentError when the string length is longer than _limit_. - * You can stop this check by passing `limit: nil`, but note that - * it may take a long time to parse. + * d = Date.new(2001, 2, 3) + * s = d.rfc3339 # => "2001-02-03T00:00:00+00:00" + * Date._rfc3339(s) + * # => {:year=>2001, :mon=>2, :mday=>3, :hour=>0, :min=>0, :sec=>0, :zone=>"+00:00", :offset=>0} + * + * See argument {limit}[rdoc-ref:Date@Argument+limit]. + * + * Related: Date.rfc3339 (returns a \Date object). */ static VALUE date_s__rfc3339(int argc, VALUE *argv, VALUE klass) @@ -4641,16 +4697,20 @@ date_s__rfc3339(int argc, VALUE *argv, VALUE klass) * call-seq: * Date.rfc3339(string = '-4712-01-01T00:00:00+00:00', start = Date::ITALY, limit: 128) -> date * - * Creates a new Date object by parsing from a string according to - * some typical RFC 3339 formats. + * Returns a new \Date object with values parsed from +string+, + * which should be a valid + * {RFC 3339 format}[https://datatracker.ietf.org/doc/html/rfc3339]: * - * Date.rfc3339('2001-02-03T04:05:06+07:00') #=> # + * d = Date.new(2001, 2, 3) + * s = d.rfc3339 # => "2001-02-03T00:00:00+00:00" + * Date.rfc3339(s) # => # * - * Raise an ArgumentError when the string length is longer than _limit_. - * You can stop this check by passing `limit: nil`, but note that - * it may take a long time to parse. + * See: * - * See argument {start}[rdoc-ref:Date@Argument+start]. + * - Argument {start}[rdoc-ref:Date@Argument+start]. + * - Argument {limit}[rdoc-ref:Date@Argument+limit]. + * + * Related: Date._rfc3339 (returns a hash). */ static VALUE date_s_rfc3339(int argc, VALUE *argv, VALUE klass) @@ -4681,11 +4741,16 @@ date_s_rfc3339(int argc, VALUE *argv, VALUE klass) * call-seq: * Date._xmlschema(string, limit: 128) -> hash * - * Returns a hash of parsed elements. + * Returns a hash of values parsed from +string+, which should be a valid + * XML date format: * - * Raise an ArgumentError when the string length is longer than _limit_. - * You can stop this check by passing `limit: nil`, but note that - * it may take a long time to parse. + * d = Date.new(2001, 2, 3) + * s = d.xmlschema # => "2001-02-03" + * Date._xmlschema(s) # => {:year=>2001, :mon=>2, :mday=>3} + * + * See argument {limit}[rdoc-ref:Date@Argument+limit]. + * + * Related: Date.xmlschema (returns a \Date object). */ static VALUE date_s__xmlschema(int argc, VALUE *argv, VALUE klass) @@ -4702,17 +4767,19 @@ date_s__xmlschema(int argc, VALUE *argv, VALUE klass) * call-seq: * Date.xmlschema(string = '-4712-01-01', start = Date::ITALY, limit: 128) -> date * - * Creates a new Date object by parsing from a string according to - * some typical XML Schema formats. + * Returns a new \Date object with values parsed from +string+, + * which should be a valid XML date format: * - * Date.xmlschema('2001-02-03') #=> # + * d = Date.new(2001, 2, 3) + * s = d.xmlschema # => "2001-02-03" + * Date.xmlschema(s) # => # * - * Raise an ArgumentError when the string length is longer than _limit_. - * You can stop this check by passing `limit: nil`, but note that - * it may take a long time to parse. + * See: * - * See argument {start}[rdoc-ref:Date@Argument+start]. + * - Argument {start}[rdoc-ref:Date@Argument+start]. + * - Argument {limit}[rdoc-ref:Date@Argument+limit]. * + * Related: Date._xmlschema (returns a hash). */ static VALUE date_s_xmlschema(int argc, VALUE *argv, VALUE klass) @@ -4743,13 +4810,19 @@ date_s_xmlschema(int argc, VALUE *argv, VALUE klass) * call-seq: * Date._rfc2822(string, limit: 128) -> hash * - * Returns a hash of parsed elements. + * Returns a hash of values parsed from +string+, which should be a valid + * {RFC 2822 date format}[https://datatracker.ietf.org/doc/html/rfc2822]: * - * Raise an ArgumentError when the string length is longer than _limit_. - * You can stop this check by passing `limit: nil`, but note that - * it may take a long time to parse. + * d = Date.new(2001, 2, 3) + * s = d.rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000" + * Date._rfc2822(s) + * # => {:wday=>6, :mday=>3, :mon=>2, :year=>2001, :hour=>0, :min=>0, :sec=>0, :zone=>"+0000", :offset=>0} + * + * See argument {limit}[rdoc-ref:Date@Argument+limit]. * * Date._rfc822 is an alias for Date._rfc2822. + * + * Related: Date.rfc2822 (returns a \Date object). */ static VALUE date_s__rfc2822(int argc, VALUE *argv, VALUE klass) @@ -4766,19 +4839,22 @@ date_s__rfc2822(int argc, VALUE *argv, VALUE klass) * call-seq: * Date.rfc2822(string = 'Mon, 1 Jan -4712 00:00:00 +0000', start = Date::ITALY, limit: 128) -> date * - * Creates a new Date object by parsing from a string according to - * some typical RFC 2822 formats. + * Returns a new \Date object with values parsed from +string+, + * which should be a valid + * {RFC 2822 date format}[https://datatracker.ietf.org/doc/html/rfc2822]: * - * Date.rfc2822('Sat, 3 Feb 2001 00:00:00 +0000') - * #=> # + * d = Date.new(2001, 2, 3) + * s = d.rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000" + * Date.rfc2822(s) # => # * - * Raise an ArgumentError when the string length is longer than _limit_. - * You can stop this check by passing `limit: nil`, but note that - * it may take a long time to parse. + * See: * - * See argument {start}[rdoc-ref:Date@Argument+start]. + * - Argument {start}[rdoc-ref:Date@Argument+start]. + * - Argument {limit}[rdoc-ref:Date@Argument+limit]. * * Date.rfc822 is an alias for Date.rfc2822. + * + * Related: Date._rfc2822 (returns a hash). */ static VALUE date_s_rfc2822(int argc, VALUE *argv, VALUE klass) @@ -4808,11 +4884,15 @@ date_s_rfc2822(int argc, VALUE *argv, VALUE klass) * call-seq: * Date._httpdate(string, limit: 128) -> hash * - * Returns a hash of parsed elements. + * Returns a hash of values parsed from +string+, which should be a valid + * HTTP date format: * - * Raise an ArgumentError when the string length is longer than _limit_. - * You can stop this check by passing `limit: nil`, but note that - * it may take a long time to parse. + * d = Date.new(2001, 2, 3) + * s = d.httpdate # => "Sat, 03 Feb 2001 00:00:00 GMT" + * Date._httpdate(s) + * # => {:wday=>6, :mday=>3, :mon=>2, :year=>2001, :hour=>0, :min=>0, :sec=>0, :zone=>"GMT", :offset=>0} + * + * Related: Date.httpdate (returns a \Date object). */ static VALUE date_s__httpdate(int argc, VALUE *argv, VALUE klass) @@ -4829,18 +4909,20 @@ date_s__httpdate(int argc, VALUE *argv, VALUE klass) * call-seq: * Date.httpdate(string = 'Mon, 01 Jan -4712 00:00:00 GMT', start = Date::ITALY, limit: 128) -> date * - * Creates a new Date object by parsing from a string according to - * some RFC 2616 format. + * Returns a new \Date object with values parsed from +string+, + * which should be a valid + * {RFC 2616 date format}[https://datatracker.ietf.org/doc/html/rfc2616]: * - * Date.httpdate('Sat, 03 Feb 2001 00:00:00 GMT') - * #=> # + * d = Date.new(2001, 2, 3) + s = d.httpdate # => "Sat, 03 Feb 2001 00:00:00 GMT" + Date.httpdate(s) # => # * - * Raise an ArgumentError when the string length is longer than _limit_. - * You can stop this check by passing `limit: nil`, but note that - * it may take a long time to parse. + * See: * - * See argument {start}[rdoc-ref:Date@Argument+start]. + * - Argument {start}[rdoc-ref:Date@Argument+start]. + * - Argument {limit}[rdoc-ref:Date@Argument+limit]. * + * Related: Date._httpdate (returns a hash). */ static VALUE date_s_httpdate(int argc, VALUE *argv, VALUE klass) @@ -4870,11 +4952,16 @@ date_s_httpdate(int argc, VALUE *argv, VALUE klass) * call-seq: * Date._jisx0301(string, limit: 128) -> hash * - * Returns a hash of parsed elements. + * Returns a hash of values parsed from +string+, which should be a valid + * JIS X 0301 date format: * - * Raise an ArgumentError when the string length is longer than _limit_. - * You can stop this check by passing `limit: nil`, but note that - * it may take a long time to parse. + * d = Date.new(2001, 2, 3) + * s = d.jisx0301 # => "H13.02.03" + * Date._jisx0301(s) # => {:year=>2001, :mon=>2, :mday=>3} + * + * See argument {limit}[rdoc-ref:Date@Argument+limit]. + * + * Related: Date.jisx0301 (returns a \Date object). */ static VALUE date_s__jisx0301(int argc, VALUE *argv, VALUE klass) @@ -4891,21 +4978,23 @@ date_s__jisx0301(int argc, VALUE *argv, VALUE klass) * call-seq: * Date.jisx0301(string = '-4712-01-01', start = Date::ITALY, limit: 128) -> date * - * Creates a new Date object by parsing from a string according to - * some typical JIS X 0301 formats. + * Returns a new \Date object with values parsed from +string+, + * which should be a valid JIS X 0301 format: * - * Date.jisx0301('H13.02.03') #=> # + * d = Date.new(2001, 2, 3) + * s = d.jisx0301 # => "H13.02.03" + * Date.jisx0301(s) # => # * * For no-era year, legacy format, Heisei is assumed. * - * Date.jisx0301('13.02.03') #=> # + * Date.jisx0301('13.02.03') # => # * - * Raise an ArgumentError when the string length is longer than _limit_. - * You can stop this check by passing `limit: nil`, but note that - * it may take a long time to parse. + * See: * - * See argument {start}[rdoc-ref:Date@Argument+start]. + * - Argument {start}[rdoc-ref:Date@Argument+start]. + * - Argument {limit}[rdoc-ref:Date@Argument+limit]. * + * Related: Date._jisx0301 (returns a hash). */ static VALUE date_s_jisx0301(int argc, VALUE *argv, VALUE klass) @@ -5097,6 +5186,7 @@ d_lite_initialize_copy(VALUE copy, VALUE date) } #ifndef NDEBUG +/* :nodoc: */ static VALUE d_lite_fill(VALUE self) { @@ -5342,6 +5432,7 @@ d_lite_cwday(VALUE self) } #ifndef NDEBUG +/* :nodoc: */ static VALUE d_lite_wnum0(VALUE self) { @@ -5349,6 +5440,7 @@ d_lite_wnum0(VALUE self) return INT2FIX(m_wnum0(dat)); } +/* :nodoc: */ static VALUE d_lite_wnum1(VALUE self) { @@ -5465,6 +5557,7 @@ d_lite_saturday_p(VALUE self) } #ifndef NDEBUG +/* :nodoc: */ static VALUE d_lite_nth_kday_p(VALUE self, VALUE n, VALUE k) { @@ -6315,9 +6408,9 @@ d_lite_prev_day(int argc, VALUE *argv, VALUE self) * * Returns a new \Date object representing the following day: * - * d = Date.today - * d.to_s # => "2022-07-11" - * d.next.to_s # => "2022-07-12" + * d = Date.new(2001, 2, 3) + * d.to_s # => "2001-02-03" + * d.next.to_s # => "2001-02-04" * * Date#succ is an alias for Date#next. */ @@ -6679,19 +6772,43 @@ cmp_dd(VALUE self, VALUE other) /* * call-seq: - * d <=> other -> -1, 0, +1 or nil + * self <=> other -> -1, 0, 1 or nil + * + * Compares +self+ and +other+, returning: + * + * - -1 if +other+ is larger. + * - 0 if the two are equal. + * - 1 if +other+ is smaller. + * - +nil+ if the two are incomparable. + * + * Argument +other+ may be: + * + * - Another \Date object: + * + * d = Date.new(2022, 7, 27) # => # + * prev_date = d.prev_day # => # + * next_date = d.next_day # => # + * d <=> next_date # => -1 + * d <=> d # => 0 + * d <=> prev_date # => 1 + * + * - A DateTime object: + * + * d <=> DateTime.new(2022, 7, 26) # => 1 + * d <=> DateTime.new(2022, 7, 27) # => 0 + * d <=> DateTime.new(2022, 7, 28) # => -1 + * + * - A numeric (compares self.ajd to +other+): + * + * d <=> 2459788 # => -1 + * d <=> 2459787 # => 1 + * d <=> 2459786 # => 1 + * d <=> d.ajd # => 0 * - * Compares the two dates and returns -1, zero, 1 or nil. The other - * should be a date object or a numeric value as an astronomical - * Julian day number. + * - Any other object: * - * Date.new(2001,2,3) <=> Date.new(2001,2,4) #=> -1 - * Date.new(2001,2,3) <=> Date.new(2001,2,3) #=> 0 - * Date.new(2001,2,3) <=> Date.new(2001,2,2) #=> 1 - * Date.new(2001,2,3) <=> Object.new #=> nil - * Date.new(2001,2,3) <=> Rational(4903887,2) #=> 0 + * d <=> Object.new # => nil * - * See also Comparable. */ static VALUE d_lite_cmp(VALUE self, VALUE other) @@ -6751,20 +6868,39 @@ equal_gen(VALUE self, VALUE other) /* * call-seq: - * d === other -> bool - * - * Returns true if they are the same day. - * - * Date.new(2001,2,3) === Date.new(2001,2,3) - * #=> true - * Date.new(2001,2,3) === Date.new(2001,2,4) - * #=> false - * DateTime.new(2001,2,3) === DateTime.new(2001,2,3,12) - * #=> true - * DateTime.new(2001,2,3) === DateTime.new(2001,2,3,0,0,0,'+24:00') - * #=> true - * DateTime.new(2001,2,3) === DateTime.new(2001,2,4,0,0,0,'+24:00') - * #=> false + * self === other -> true, false, or nil. + * + * Returns +true+ if +self+ and +other+ represent the same date, + * +false+ if not, +nil+ if the two are not comparable. + * + * Argument +other+ may be: + * + * - Another \Date object: + * + * d = Date.new(2022, 7, 27) # => # + * prev_date = d.prev_day # => # + * next_date = d.next_day # => # + * d === prev_date # => false + * d === d # => true + * d === next_date # => false + * + * - A DateTime object: + * + * d === DateTime.new(2022, 7, 26) # => false + * d === DateTime.new(2022, 7, 27) # => true + * d === DateTime.new(2022, 7, 28) # => false + * + * - A numeric (compares self.jd to +other+): + * + * d === 2459788 # => true + * d === 2459787 # => false + * d === 2459786 # => false + * d === d.jd # => true + * + * - An object not comparable: + * + * d === Object.new # => nil + * */ static VALUE d_lite_equal(VALUE self, VALUE other) @@ -6827,12 +6963,14 @@ static VALUE strftimev(const char *, VALUE, /* * call-seq: - * d.to_s -> string + * to_s -> string * - * Returns a string in an ISO 8601 format. (This method doesn't use the - * expanded representations.) + * Returns a string representation of the date in +self+ + * in {ISO 8601 extended date format}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html#label-ISO+8601+Format+Specifications] + * ('%Y-%m-%d'): + * + * Date.new(2001, 2, 3).to_s # => "2001-02-03" * - * Date.new(2001,2,3).to_s #=> "2001-02-03" */ static VALUE d_lite_to_s(VALUE self) @@ -6841,6 +6979,7 @@ d_lite_to_s(VALUE self) } #ifndef NDEBUG +/* :nodoc: */ static VALUE mk_inspect_raw(union DateData *x, VALUE klass) { @@ -6890,6 +7029,7 @@ mk_inspect_raw(union DateData *x, VALUE klass) } } +/* :nodoc: */ static VALUE d_lite_inspect_raw(VALUE self) { @@ -6911,14 +7051,13 @@ mk_inspect(union DateData *x, VALUE klass, VALUE to_s) /* * call-seq: - * d.inspect -> string + * inspect -> string * - * Returns the value as a string for inspection. + * Returns a string representation of +self+: + * + * Date.new(2001, 2, 3).inspect + * # => "#" * - * Date.new(2001,2,3).inspect - * #=> "#" - * DateTime.new(2001,2,3,4,5,6,'-7').inspect - * #=> "#" */ static VALUE d_lite_inspect(VALUE self) @@ -7100,12 +7239,12 @@ date_strftime_internal(int argc, VALUE *argv, VALUE self, /* * call-seq: - * strftime(format = '%F') -> string + * strftime(format = '%F') -> string * - * Returns a string representation of +self+, + * Returns a string representation of the date in +self+, * formatted according the given +format+: * - * Date.today.strftime # => "2022-07-01" + * Date.new(2001, 2, 3).strftime # => "2001-02-03" * * For other formats, see * {Formats for Dates and Times}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html]. @@ -7137,13 +7276,17 @@ strftimev(const char *fmt, VALUE self, /* * call-seq: - * d.asctime -> string - * d.ctime -> string + * asctime -> string + * + * Equivalent to #strftime with argument '%a %b %e %T %Y' + * (or its {shorthand form}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html#label-Shorthand+Conversion+Specifiers] + * '%c'): * - * Returns a string in asctime(3) format (but without "\n\0" at the - * end). This method is equivalent to strftime('%c'). + * Date.new(2001, 2, 3).asctime # => "Sat Feb 3 00:00:00 2001" * - * See also asctime(3) or ctime(3). + * See {asctime}[https://linux.die.net/man/3/asctime]. + * + * Date#ctime is an alias for Date#asctime. */ static VALUE d_lite_asctime(VALUE self) @@ -7153,10 +7296,15 @@ d_lite_asctime(VALUE self) /* * call-seq: - * d.iso8601 -> string - * d.xmlschema -> string + * iso8601 -> string + * + * Equivalent to #strftime with argument '%Y-%m-%d' + * (or its {shorthand form}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html#label-Shorthand+Conversion+Specifiers] + * '%F'); * - * This method is equivalent to strftime('%F'). + * Date.new(2001, 2, 3).iso8601 # => "2001-02-03" + * + * Date#xmlschema is an alias for Date#iso8601. */ static VALUE d_lite_iso8601(VALUE self) @@ -7166,9 +7314,13 @@ d_lite_iso8601(VALUE self) /* * call-seq: - * d.rfc3339 -> string + * rfc3339 -> string + * + * Equivalent to #strftime with argument '%FT%T%:z'; + * see {Formats for Dates and Times}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html]: + * + * Date.new(2001, 2, 3).rfc3339 # => "2001-02-03T00:00:00+00:00" * - * This method is equivalent to strftime('%FT%T%:z'). */ static VALUE d_lite_rfc3339(VALUE self) @@ -7178,10 +7330,14 @@ d_lite_rfc3339(VALUE self) /* * call-seq: - * d.rfc2822 -> string - * d.rfc822 -> string + * rfc2822 -> string + * + * Equivalent to #strftime with argument '%a, %-d %b %Y %T %z'; + * see {Formats for Dates and Times}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html]: + * + * Date.new(2001, 2, 3).rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000" * - * This method is equivalent to strftime('%a, %-d %b %Y %T %z'). + * Date#rfc822 is an alias for Date#rfc2822. */ static VALUE d_lite_rfc2822(VALUE self) @@ -7191,10 +7347,13 @@ d_lite_rfc2822(VALUE self) /* * call-seq: - * d.httpdate -> string + * httpdate -> string + * + * Equivalent to #strftime with argument '%a, %d %b %Y %T GMT'; + * see {Formats for Dates and Times}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html]: + * + * Date.new(2001, 2, 3).httpdate # => "Sat, 03 Feb 2001 00:00:00 GMT" * - * This method is equivalent to strftime('%a, %d %b %Y %T GMT'). - * See also RFC 2616. */ static VALUE d_lite_httpdate(VALUE self) @@ -7245,11 +7404,13 @@ jisx0301_date_format(char *fmt, size_t size, VALUE jd, VALUE y) /* * call-seq: - * d.jisx0301 -> string + * jisx0301 -> string * - * Returns a string in a JIS X 0301 format. + * Returns a string representation of the date in +self+ + * in JIS X 0301 format. + * + * Date.new(2001, 2, 3).jisx0301 # => "H13.02.03" * - * Date.new(2001,2,3).jisx0301 #=> "H13.02.03" */ static VALUE d_lite_jisx0301(VALUE self) @@ -7265,6 +7426,7 @@ d_lite_jisx0301(VALUE self) } #ifndef NDEBUG +/* :nodoc: */ static VALUE d_lite_marshal_dump_old(VALUE self) { @@ -7551,6 +7713,9 @@ datetime_s_ordinal(int argc, VALUE *argv, VALUE klass) return ret; } +/* + * Same as DateTime.new. + */ static VALUE datetime_s_civil(int argc, VALUE *argv, VALUE klass) { @@ -7739,6 +7904,7 @@ datetime_s_commercial(int argc, VALUE *argv, VALUE klass) } #ifndef NDEBUG +/* :nodoc: */ static VALUE datetime_s_weeknum(int argc, VALUE *argv, VALUE klass) { @@ -7808,6 +7974,7 @@ datetime_s_weeknum(int argc, VALUE *argv, VALUE klass) return ret; } +/* :nodoc: */ static VALUE datetime_s_nth_kday(int argc, VALUE *argv, VALUE klass) { @@ -8153,9 +8320,9 @@ datetime_s_strptime(int argc, VALUE *argv, VALUE klass) * Parses the given representation of date and time, and creates a * DateTime object. * - * This method *does not* function as a validator. If the input + * This method *does* *not* function as a validator. If the input * string does not match valid formats strictly, you may get a cryptic - * result. Should consider to use `DateTime.strptime` instead of this + * result. Should consider to use DateTime.strptime instead of this * method as possible. * * If the optional second argument is true and the detected year is in @@ -8169,8 +8336,8 @@ datetime_s_strptime(int argc, VALUE *argv, VALUE klass) * #=> # * * Raise an ArgumentError when the string length is longer than _limit_. - * You can stop this check by passing `limit: nil`, but note that - * it may take a long time to parse. + * You can stop this check by passing limit: nil, but note + * that it may take a long time to parse. */ static VALUE datetime_s_parse(int argc, VALUE *argv, VALUE klass) @@ -8216,8 +8383,8 @@ datetime_s_parse(int argc, VALUE *argv, VALUE klass) * #=> # * * Raise an ArgumentError when the string length is longer than _limit_. - * You can stop this check by passing `limit: nil`, but note that - * it may take a long time to parse. + * You can stop this check by passing limit: nil, but note + * that it may take a long time to parse. */ static VALUE datetime_s_iso8601(int argc, VALUE *argv, VALUE klass) @@ -8256,8 +8423,8 @@ datetime_s_iso8601(int argc, VALUE *argv, VALUE klass) * #=> # * * Raise an ArgumentError when the string length is longer than _limit_. - * You can stop this check by passing `limit: nil`, but note that - * it may take a long time to parse. + * You can stop this check by passing limit: nil, but note + * that it may take a long time to parse. */ static VALUE datetime_s_rfc3339(int argc, VALUE *argv, VALUE klass) @@ -8296,8 +8463,8 @@ datetime_s_rfc3339(int argc, VALUE *argv, VALUE klass) * #=> # * * Raise an ArgumentError when the string length is longer than _limit_. - * You can stop this check by passing `limit: nil`, but note that - * it may take a long time to parse. + * You can stop this check by passing limit: nil, but note + * that it may take a long time to parse. */ static VALUE datetime_s_xmlschema(int argc, VALUE *argv, VALUE klass) @@ -8337,8 +8504,8 @@ datetime_s_xmlschema(int argc, VALUE *argv, VALUE klass) * #=> # * * Raise an ArgumentError when the string length is longer than _limit_. - * You can stop this check by passing `limit: nil`, but note that - * it may take a long time to parse. + * You can stop this check by passing limit: nil, but note + * that it may take a long time to parse. */ static VALUE datetime_s_rfc2822(int argc, VALUE *argv, VALUE klass) @@ -8377,8 +8544,8 @@ datetime_s_rfc2822(int argc, VALUE *argv, VALUE klass) * #=> # * * Raise an ArgumentError when the string length is longer than _limit_. - * You can stop this check by passing `limit: nil`, but note that - * it may take a long time to parse. + * You can stop this check by passing limit: nil, but note + * that it may take a long time to parse. */ static VALUE datetime_s_httpdate(int argc, VALUE *argv, VALUE klass) @@ -8422,8 +8589,8 @@ datetime_s_httpdate(int argc, VALUE *argv, VALUE klass) * #=> # * * Raise an ArgumentError when the string length is longer than _limit_. - * You can stop this check by passing `limit: nil`, but note that - * it may take a long time to parse. + * You can stop this check by passing limit: nil, but note + * that it may take a long time to parse. */ static VALUE datetime_s_jisx0301(int argc, VALUE *argv, VALUE klass) @@ -8657,10 +8824,15 @@ time_to_datetime(VALUE self) /* * call-seq: - * d.to_time -> time + * to_time -> time + * + * Returns a new Time object with the same value as +self+; + * if +self+ is a Julian date, derives its Gregorian date + * for conversion to the \Time object: + * + * Date.new(2001, 2, 3).to_time # => 2001-02-03 00:00:00 -0600 + * Date.new(2001, 2, 3, Date::JULIAN).to_time # => 2001-02-16 00:00:00 -0600 * - * Returns a Time object which denotes self. If self is a julian date, - * convert it to a gregorian date before converting it to Time. */ static VALUE date_to_time(VALUE self) @@ -8681,9 +8853,9 @@ date_to_time(VALUE self) /* * call-seq: - * d.to_date -> self + * to_date -> self * - * Returns self. + * Returns +self+. */ static VALUE date_to_date(VALUE self) @@ -8695,7 +8867,10 @@ date_to_date(VALUE self) * call-seq: * d.to_datetime -> datetime * - * Returns a DateTime object which denotes self. + * Returns a DateTime whose value is the same as +self+: + * + * Date.new(2001, 2, 3).to_datetime # => # + * */ static VALUE date_to_datetime(VALUE self) @@ -8813,6 +8988,7 @@ datetime_to_datetime(VALUE self) #define MIN_JD -327 #define MAX_JD 366963925 +/* :nodoc: */ static int test_civil(int from, int to, double sg) { @@ -8833,6 +9009,7 @@ test_civil(int from, int to, double sg) return 1; } +/* :nodoc: */ static VALUE date_s_test_civil(VALUE klass) { @@ -8853,6 +9030,7 @@ date_s_test_civil(VALUE klass) return Qtrue; } +/* :nodoc: */ static int test_ordinal(int from, int to, double sg) { @@ -8873,6 +9051,7 @@ test_ordinal(int from, int to, double sg) return 1; } +/* :nodoc: */ static VALUE date_s_test_ordinal(VALUE klass) { @@ -8893,6 +9072,7 @@ date_s_test_ordinal(VALUE klass) return Qtrue; } +/* :nodoc: */ static int test_commercial(int from, int to, double sg) { @@ -8913,6 +9093,7 @@ test_commercial(int from, int to, double sg) return 1; } +/* :nodoc: */ static VALUE date_s_test_commercial(VALUE klass) { @@ -8933,6 +9114,7 @@ date_s_test_commercial(VALUE klass) return Qtrue; } +/* :nodoc: */ static int test_weeknum(int from, int to, int f, double sg) { @@ -8953,6 +9135,7 @@ test_weeknum(int from, int to, int f, double sg) return 1; } +/* :nodoc: */ static VALUE date_s_test_weeknum(VALUE klass) { @@ -8977,6 +9160,7 @@ date_s_test_weeknum(VALUE klass) return Qtrue; } +/* :nodoc: */ static int test_nth_kday(int from, int to, double sg) { @@ -8997,6 +9181,7 @@ test_nth_kday(int from, int to, double sg) return 1; } +/* :nodoc: */ static VALUE date_s_test_nth_kday(VALUE klass) { @@ -9017,6 +9202,7 @@ date_s_test_nth_kday(VALUE klass) return Qtrue; } +/* :nodoc: */ static int test_unit_v2v(VALUE i, VALUE (* conv1)(VALUE), @@ -9028,6 +9214,7 @@ test_unit_v2v(VALUE i, return f_eqeq_p(o, i); } +/* :nodoc: */ static int test_unit_v2v_iter2(VALUE (* conv1)(VALUE), VALUE (* conv2)(VALUE)) @@ -9059,6 +9246,7 @@ test_unit_v2v_iter2(VALUE (* conv1)(VALUE), return 1; } +/* :nodoc: */ static int test_unit_v2v_iter(VALUE (* conv1)(VALUE), VALUE (* conv2)(VALUE)) @@ -9070,6 +9258,7 @@ test_unit_v2v_iter(VALUE (* conv1)(VALUE), return 1; } +/* :nodoc: */ static VALUE date_s_test_unit_conv(VALUE klass) { @@ -9084,6 +9273,7 @@ date_s_test_unit_conv(VALUE klass) return Qtrue; } +/* :nodoc: */ static VALUE date_s_test_all(VALUE klass) { @@ -9380,8 +9570,23 @@ Init_date_core(void) * - Date::JULIAN - no changeover date; all dates are Julian. * - Date::GREGORIAN - no changeover date; all dates are Gregorian. * + * === Argument +limit+ + * + * Certain singleton methods in \Date that parse string arguments + * also take optional keyword argument +limit+, + * which can limit the length of the string argument. + * + * When +limit+ is: + * + * - Non-negative: + * raises ArgumentError if the string length is greater than _limit_. + * - Other numeric or +nil+: ignores +limit+. + * - Other non-numeric: raises TypeError. + * */ cDate = rb_define_class("Date", rb_cObject); + + /* Exception for invalid date/time */ eDateError = rb_define_class_under(cDate, "Error", rb_eArgError); rb_include_module(cDate, rb_mComparable); diff --git a/ext/date/lib/date.rb b/ext/date/lib/date.rb index 5770187a8e3e47..88984d7bd295aa 100644 --- a/ext/date/lib/date.rb +++ b/ext/date/lib/date.rb @@ -6,6 +6,10 @@ class Date VERSION = '3.2.2' # :nodoc: + # call-seq: + # infinite? -> false + # + # Returns +false+ def infinite? false end diff --git a/ext/digest/md5/md5.c b/ext/digest/md5/md5.c index 52a787abdb20ff..3a7fe2cdad27b6 100644 --- a/ext/digest/md5/md5.c +++ b/ext/digest/md5/md5.c @@ -34,8 +34,8 @@ that follows (in reverse chronological order): 2000-07-03 lpd Patched to eliminate warnings about "constant is - unsigned in ANSI C, signed in traditional"; - made test program self-checking. + unsigned in ANSI C, signed in traditional"; + made test program self-checking. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). 1999-05-03 lpd Original version. @@ -64,32 +64,32 @@ int main(void) { static const char *const test[7*2] = { - "", "d41d8cd98f00b204e9800998ecf8427e", - "a", "0cc175b9c0f1b6a831c399e269772661", - "abc", "900150983cd24fb0d6963f7d28e17f72", - "message digest", "f96b697d7cb7938d525a2f31aaf161d0", - "abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b", - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", - "d174ab98d277d9f5a5611c2c9f419d9f", - "12345678901234567890123456789012345678901234567890123456789012345678901234567890", "57edf4a22be3c955ac49da2e2107b67a" + "", "d41d8cd98f00b204e9800998ecf8427e", + "a", "0cc175b9c0f1b6a831c399e269772661", + "abc", "900150983cd24fb0d6963f7d28e17f72", + "message digest", "f96b697d7cb7938d525a2f31aaf161d0", + "abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "d174ab98d277d9f5a5611c2c9f419d9f", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890", "57edf4a22be3c955ac49da2e2107b67a" }; int i; for (i = 0; i < 7*2; i += 2) { - MD5_CTX state; - uint8_t digest[16]; - char hex_output[16*2 + 1]; - int di; - - MD5_Init(&state); - MD5_Update(&state, (const uint8_t *)test[i], strlen(test[i])); - MD5_Final(digest, &state); - printf("MD5 (\"%s\") = ", test[i]); - for (di = 0; di < 16; ++di) - sprintf(hex_output + di * 2, "%02x", digest[di]); - puts(hex_output); - if (strcmp(hex_output, test[i + 1])) - printf("**** ERROR, should be: %s\n", test[i + 1]); + MD5_CTX state; + uint8_t digest[16]; + char hex_output[16*2 + 1]; + int di; + + MD5_Init(&state); + MD5_Update(&state, (const uint8_t *)test[i], strlen(test[i])); + MD5_Final(digest, &state); + printf("MD5 (\"%s\") = ", test[i]); + for (di = 0; di < 16; ++di) + sprintf(hex_output + di * 2, "%02x", digest[di]); + puts(hex_output); + if (strcmp(hex_output, test[i + 1])) + printf("**** ERROR, should be: %s\n", test[i + 1]); } return 0; } @@ -106,18 +106,18 @@ main(void) { int i; for (i = 1; i <= 64; ++i) { - unsigned long v = (unsigned long)(4294967296.0 * fabs(sin((double)i))); - - /* - * The following nonsense is only to avoid compiler warnings about - * "integer constant is unsigned in ANSI C, signed with -traditional". - */ - if (v >> 31) { - printf("#define T%d /* 0x%08lx */ (T_MASK ^ 0x%08lx)\n", i, - v, (unsigned long)(unsigned int)(~v)); - } else { - printf("#define T%d 0x%08lx\n", i, v); - } + unsigned long v = (unsigned long)(4294967296.0 * fabs(sin((double)i))); + + /* + * The following nonsense is only to avoid compiler warnings about + * "integer constant is unsigned in ANSI C, signed with -traditional". + */ + if (v >> 31) { + printf("#define T%d /* 0x%08lx */ (T_MASK ^ 0x%08lx)\n", i, + v, (unsigned long)(unsigned int)(~v)); + } else { + printf("#define T%d 0x%08lx\n", i, v); + } } return 0; } @@ -199,8 +199,8 @@ static void md5_process(MD5_CTX *pms, const uint8_t *data /*[64]*/) { uint32_t - a = pms->state[0], b = pms->state[1], - c = pms->state[2], d = pms->state[3]; + a = pms->state[0], b = pms->state[1], + c = pms->state[2], d = pms->state[3]; uint32_t t; #ifdef WORDS_BIGENDIAN @@ -214,7 +214,7 @@ md5_process(MD5_CTX *pms, const uint8_t *data /*[64]*/) int i; for (i = 0; i < 16; ++i, xp += 4) - X[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + X[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); #else @@ -226,12 +226,12 @@ md5_process(MD5_CTX *pms, const uint8_t *data /*[64]*/) const uint32_t *X; if (!(((uintptr_t)data) & 3)) { - /* data are properly aligned */ - X = (const uint32_t *)data; + /* data are properly aligned */ + X = (const uint32_t *)data; } else { - /* not aligned */ - memcpy(xbuf, data, 64); - X = xbuf; + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; } #endif @@ -370,55 +370,55 @@ MD5_Update(MD5_CTX *pms, const uint8_t *data, size_t nbytes) uint32_t nbits = (uint32_t)(nbytes << 3); if (nbytes == 0) - return; + return; /* Update the message length. */ pms->count[1] += nbytes >> 29; pms->count[0] += nbits; if (pms->count[0] < nbits) - pms->count[1]++; + pms->count[1]++; /* Process an initial partial block. */ if (offset) { - size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes); - - memcpy(pms->buffer + offset, p, copy); - if (offset + copy < 64) - return; - p += copy; - left -= copy; - md5_process(pms, pms->buffer); + size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buffer + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buffer); } /* Process full blocks. */ for (; left >= 64; p += 64, left -= 64) - md5_process(pms, p); + md5_process(pms, p); /* Process a final partial block. */ if (left) - memcpy(pms->buffer, p, left); + memcpy(pms->buffer, p, left); } int MD5_Finish(MD5_CTX *pms, uint8_t *digest) { static const uint8_t pad[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; uint8_t data[8]; size_t i; /* Save the length before padding. */ for (i = 0; i < 8; ++i) - data[i] = (uint8_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + data[i] = (uint8_t)(pms->count[i >> 2] >> ((i & 3) << 3)); /* Pad to 56 bytes mod 64. */ MD5_Update(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); /* Append the length. */ MD5_Update(pms, data, 8); for (i = 0; i < 16; ++i) - digest[i] = (uint8_t)(pms->state[i >> 2] >> ((i & 3) << 3)); + digest[i] = (uint8_t)(pms->state[i >> 2] >> ((i & 3) << 3)); return 1; } diff --git a/ext/digest/md5/md5.h b/ext/digest/md5/md5.h index 0b04f9fc4eab58..1b3383c5eecde7 100644 --- a/ext/digest/md5/md5.h +++ b/ext/digest/md5/md5.h @@ -34,8 +34,8 @@ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); - added conditionalization for C++ compilation from Martin - Purschke . + added conditionalization for C++ compilation from Martin + Purschke . 1999-05-03 lpd Original version. */ diff --git a/ext/digest/rmd160/rmd160.c b/ext/digest/rmd160/rmd160.c index 0ea78dcd642d0a..058d004f3a672d 100644 --- a/ext/digest/rmd160/rmd160.c +++ b/ext/digest/rmd160/rmd160.c @@ -128,17 +128,17 @@ int RMD160_Init(RMD160_CTX *context) { - _DIAGASSERT(context != NULL); - - /* ripemd-160 initialization constants */ - context->state[0] = 0x67452301U; - context->state[1] = 0xefcdab89U; - context->state[2] = 0x98badcfeU; - context->state[3] = 0x10325476U; - context->state[4] = 0xc3d2e1f0U; - context->length[0] = context->length[1] = 0; - context->buflen = 0; - return 1; + _DIAGASSERT(context != NULL); + + /* ripemd-160 initialization constants */ + context->state[0] = 0x67452301U; + context->state[1] = 0xefcdab89U; + context->state[2] = 0x98badcfeU; + context->state[3] = 0x10325476U; + context->state[4] = 0xc3d2e1f0U; + context->length[0] = context->length[1] = 0; + context->buflen = 0; + return 1; } /********************************************************************/ @@ -146,205 +146,205 @@ RMD160_Init(RMD160_CTX *context) void RMD160_Transform(uint32_t state[5], const uint32_t block[16]) { - uint32_t aa, bb, cc, dd, ee; - uint32_t aaa, bbb, ccc, ddd, eee; - - _DIAGASSERT(state != NULL); - _DIAGASSERT(block != NULL); - - aa = aaa = state[0]; - bb = bbb = state[1]; - cc = ccc = state[2]; - dd = ddd = state[3]; - ee = eee = state[4]; - - /* round 1 */ - FF(aa, bb, cc, dd, ee, block[ 0], 11); - FF(ee, aa, bb, cc, dd, block[ 1], 14); - FF(dd, ee, aa, bb, cc, block[ 2], 15); - FF(cc, dd, ee, aa, bb, block[ 3], 12); - FF(bb, cc, dd, ee, aa, block[ 4], 5); - FF(aa, bb, cc, dd, ee, block[ 5], 8); - FF(ee, aa, bb, cc, dd, block[ 6], 7); - FF(dd, ee, aa, bb, cc, block[ 7], 9); - FF(cc, dd, ee, aa, bb, block[ 8], 11); - FF(bb, cc, dd, ee, aa, block[ 9], 13); - FF(aa, bb, cc, dd, ee, block[10], 14); - FF(ee, aa, bb, cc, dd, block[11], 15); - FF(dd, ee, aa, bb, cc, block[12], 6); - FF(cc, dd, ee, aa, bb, block[13], 7); - FF(bb, cc, dd, ee, aa, block[14], 9); - FF(aa, bb, cc, dd, ee, block[15], 8); - - /* round 2 */ - GG(ee, aa, bb, cc, dd, block[ 7], 7); - GG(dd, ee, aa, bb, cc, block[ 4], 6); - GG(cc, dd, ee, aa, bb, block[13], 8); - GG(bb, cc, dd, ee, aa, block[ 1], 13); - GG(aa, bb, cc, dd, ee, block[10], 11); - GG(ee, aa, bb, cc, dd, block[ 6], 9); - GG(dd, ee, aa, bb, cc, block[15], 7); - GG(cc, dd, ee, aa, bb, block[ 3], 15); - GG(bb, cc, dd, ee, aa, block[12], 7); - GG(aa, bb, cc, dd, ee, block[ 0], 12); - GG(ee, aa, bb, cc, dd, block[ 9], 15); - GG(dd, ee, aa, bb, cc, block[ 5], 9); - GG(cc, dd, ee, aa, bb, block[ 2], 11); - GG(bb, cc, dd, ee, aa, block[14], 7); - GG(aa, bb, cc, dd, ee, block[11], 13); - GG(ee, aa, bb, cc, dd, block[ 8], 12); - - /* round 3 */ - HH(dd, ee, aa, bb, cc, block[ 3], 11); - HH(cc, dd, ee, aa, bb, block[10], 13); - HH(bb, cc, dd, ee, aa, block[14], 6); - HH(aa, bb, cc, dd, ee, block[ 4], 7); - HH(ee, aa, bb, cc, dd, block[ 9], 14); - HH(dd, ee, aa, bb, cc, block[15], 9); - HH(cc, dd, ee, aa, bb, block[ 8], 13); - HH(bb, cc, dd, ee, aa, block[ 1], 15); - HH(aa, bb, cc, dd, ee, block[ 2], 14); - HH(ee, aa, bb, cc, dd, block[ 7], 8); - HH(dd, ee, aa, bb, cc, block[ 0], 13); - HH(cc, dd, ee, aa, bb, block[ 6], 6); - HH(bb, cc, dd, ee, aa, block[13], 5); - HH(aa, bb, cc, dd, ee, block[11], 12); - HH(ee, aa, bb, cc, dd, block[ 5], 7); - HH(dd, ee, aa, bb, cc, block[12], 5); - - /* round 4 */ - II(cc, dd, ee, aa, bb, block[ 1], 11); - II(bb, cc, dd, ee, aa, block[ 9], 12); - II(aa, bb, cc, dd, ee, block[11], 14); - II(ee, aa, bb, cc, dd, block[10], 15); - II(dd, ee, aa, bb, cc, block[ 0], 14); - II(cc, dd, ee, aa, bb, block[ 8], 15); - II(bb, cc, dd, ee, aa, block[12], 9); - II(aa, bb, cc, dd, ee, block[ 4], 8); - II(ee, aa, bb, cc, dd, block[13], 9); - II(dd, ee, aa, bb, cc, block[ 3], 14); - II(cc, dd, ee, aa, bb, block[ 7], 5); - II(bb, cc, dd, ee, aa, block[15], 6); - II(aa, bb, cc, dd, ee, block[14], 8); - II(ee, aa, bb, cc, dd, block[ 5], 6); - II(dd, ee, aa, bb, cc, block[ 6], 5); - II(cc, dd, ee, aa, bb, block[ 2], 12); - - /* round 5 */ - JJ(bb, cc, dd, ee, aa, block[ 4], 9); - JJ(aa, bb, cc, dd, ee, block[ 0], 15); - JJ(ee, aa, bb, cc, dd, block[ 5], 5); - JJ(dd, ee, aa, bb, cc, block[ 9], 11); - JJ(cc, dd, ee, aa, bb, block[ 7], 6); - JJ(bb, cc, dd, ee, aa, block[12], 8); - JJ(aa, bb, cc, dd, ee, block[ 2], 13); - JJ(ee, aa, bb, cc, dd, block[10], 12); - JJ(dd, ee, aa, bb, cc, block[14], 5); - JJ(cc, dd, ee, aa, bb, block[ 1], 12); - JJ(bb, cc, dd, ee, aa, block[ 3], 13); - JJ(aa, bb, cc, dd, ee, block[ 8], 14); - JJ(ee, aa, bb, cc, dd, block[11], 11); - JJ(dd, ee, aa, bb, cc, block[ 6], 8); - JJ(cc, dd, ee, aa, bb, block[15], 5); - JJ(bb, cc, dd, ee, aa, block[13], 6); - - /* parallel round 1 */ - JJJ(aaa, bbb, ccc, ddd, eee, block[ 5], 8); - JJJ(eee, aaa, bbb, ccc, ddd, block[14], 9); - JJJ(ddd, eee, aaa, bbb, ccc, block[ 7], 9); - JJJ(ccc, ddd, eee, aaa, bbb, block[ 0], 11); - JJJ(bbb, ccc, ddd, eee, aaa, block[ 9], 13); - JJJ(aaa, bbb, ccc, ddd, eee, block[ 2], 15); - JJJ(eee, aaa, bbb, ccc, ddd, block[11], 15); - JJJ(ddd, eee, aaa, bbb, ccc, block[ 4], 5); - JJJ(ccc, ddd, eee, aaa, bbb, block[13], 7); - JJJ(bbb, ccc, ddd, eee, aaa, block[ 6], 7); - JJJ(aaa, bbb, ccc, ddd, eee, block[15], 8); - JJJ(eee, aaa, bbb, ccc, ddd, block[ 8], 11); - JJJ(ddd, eee, aaa, bbb, ccc, block[ 1], 14); - JJJ(ccc, ddd, eee, aaa, bbb, block[10], 14); - JJJ(bbb, ccc, ddd, eee, aaa, block[ 3], 12); - JJJ(aaa, bbb, ccc, ddd, eee, block[12], 6); - - /* parallel round 2 */ - III(eee, aaa, bbb, ccc, ddd, block[ 6], 9); - III(ddd, eee, aaa, bbb, ccc, block[11], 13); - III(ccc, ddd, eee, aaa, bbb, block[ 3], 15); - III(bbb, ccc, ddd, eee, aaa, block[ 7], 7); - III(aaa, bbb, ccc, ddd, eee, block[ 0], 12); - III(eee, aaa, bbb, ccc, ddd, block[13], 8); - III(ddd, eee, aaa, bbb, ccc, block[ 5], 9); - III(ccc, ddd, eee, aaa, bbb, block[10], 11); - III(bbb, ccc, ddd, eee, aaa, block[14], 7); - III(aaa, bbb, ccc, ddd, eee, block[15], 7); - III(eee, aaa, bbb, ccc, ddd, block[ 8], 12); - III(ddd, eee, aaa, bbb, ccc, block[12], 7); - III(ccc, ddd, eee, aaa, bbb, block[ 4], 6); - III(bbb, ccc, ddd, eee, aaa, block[ 9], 15); - III(aaa, bbb, ccc, ddd, eee, block[ 1], 13); - III(eee, aaa, bbb, ccc, ddd, block[ 2], 11); - - /* parallel round 3 */ - HHH(ddd, eee, aaa, bbb, ccc, block[15], 9); - HHH(ccc, ddd, eee, aaa, bbb, block[ 5], 7); - HHH(bbb, ccc, ddd, eee, aaa, block[ 1], 15); - HHH(aaa, bbb, ccc, ddd, eee, block[ 3], 11); - HHH(eee, aaa, bbb, ccc, ddd, block[ 7], 8); - HHH(ddd, eee, aaa, bbb, ccc, block[14], 6); - HHH(ccc, ddd, eee, aaa, bbb, block[ 6], 6); - HHH(bbb, ccc, ddd, eee, aaa, block[ 9], 14); - HHH(aaa, bbb, ccc, ddd, eee, block[11], 12); - HHH(eee, aaa, bbb, ccc, ddd, block[ 8], 13); - HHH(ddd, eee, aaa, bbb, ccc, block[12], 5); - HHH(ccc, ddd, eee, aaa, bbb, block[ 2], 14); - HHH(bbb, ccc, ddd, eee, aaa, block[10], 13); - HHH(aaa, bbb, ccc, ddd, eee, block[ 0], 13); - HHH(eee, aaa, bbb, ccc, ddd, block[ 4], 7); - HHH(ddd, eee, aaa, bbb, ccc, block[13], 5); - - /* parallel round 4 */ - GGG(ccc, ddd, eee, aaa, bbb, block[ 8], 15); - GGG(bbb, ccc, ddd, eee, aaa, block[ 6], 5); - GGG(aaa, bbb, ccc, ddd, eee, block[ 4], 8); - GGG(eee, aaa, bbb, ccc, ddd, block[ 1], 11); - GGG(ddd, eee, aaa, bbb, ccc, block[ 3], 14); - GGG(ccc, ddd, eee, aaa, bbb, block[11], 14); - GGG(bbb, ccc, ddd, eee, aaa, block[15], 6); - GGG(aaa, bbb, ccc, ddd, eee, block[ 0], 14); - GGG(eee, aaa, bbb, ccc, ddd, block[ 5], 6); - GGG(ddd, eee, aaa, bbb, ccc, block[12], 9); - GGG(ccc, ddd, eee, aaa, bbb, block[ 2], 12); - GGG(bbb, ccc, ddd, eee, aaa, block[13], 9); - GGG(aaa, bbb, ccc, ddd, eee, block[ 9], 12); - GGG(eee, aaa, bbb, ccc, ddd, block[ 7], 5); - GGG(ddd, eee, aaa, bbb, ccc, block[10], 15); - GGG(ccc, ddd, eee, aaa, bbb, block[14], 8); - - /* parallel round 5 */ - FFF(bbb, ccc, ddd, eee, aaa, block[12] , 8); - FFF(aaa, bbb, ccc, ddd, eee, block[15] , 5); - FFF(eee, aaa, bbb, ccc, ddd, block[10] , 12); - FFF(ddd, eee, aaa, bbb, ccc, block[ 4] , 9); - FFF(ccc, ddd, eee, aaa, bbb, block[ 1] , 12); - FFF(bbb, ccc, ddd, eee, aaa, block[ 5] , 5); - FFF(aaa, bbb, ccc, ddd, eee, block[ 8] , 14); - FFF(eee, aaa, bbb, ccc, ddd, block[ 7] , 6); - FFF(ddd, eee, aaa, bbb, ccc, block[ 6] , 8); - FFF(ccc, ddd, eee, aaa, bbb, block[ 2] , 13); - FFF(bbb, ccc, ddd, eee, aaa, block[13] , 6); - FFF(aaa, bbb, ccc, ddd, eee, block[14] , 5); - FFF(eee, aaa, bbb, ccc, ddd, block[ 0] , 15); - FFF(ddd, eee, aaa, bbb, ccc, block[ 3] , 13); - FFF(ccc, ddd, eee, aaa, bbb, block[ 9] , 11); - FFF(bbb, ccc, ddd, eee, aaa, block[11] , 11); - - /* combine results */ - ddd += cc + state[1]; /* final result for state[0] */ - state[1] = state[2] + dd + eee; - state[2] = state[3] + ee + aaa; - state[3] = state[4] + aa + bbb; - state[4] = state[0] + bb + ccc; - state[0] = ddd; + uint32_t aa, bb, cc, dd, ee; + uint32_t aaa, bbb, ccc, ddd, eee; + + _DIAGASSERT(state != NULL); + _DIAGASSERT(block != NULL); + + aa = aaa = state[0]; + bb = bbb = state[1]; + cc = ccc = state[2]; + dd = ddd = state[3]; + ee = eee = state[4]; + + /* round 1 */ + FF(aa, bb, cc, dd, ee, block[ 0], 11); + FF(ee, aa, bb, cc, dd, block[ 1], 14); + FF(dd, ee, aa, bb, cc, block[ 2], 15); + FF(cc, dd, ee, aa, bb, block[ 3], 12); + FF(bb, cc, dd, ee, aa, block[ 4], 5); + FF(aa, bb, cc, dd, ee, block[ 5], 8); + FF(ee, aa, bb, cc, dd, block[ 6], 7); + FF(dd, ee, aa, bb, cc, block[ 7], 9); + FF(cc, dd, ee, aa, bb, block[ 8], 11); + FF(bb, cc, dd, ee, aa, block[ 9], 13); + FF(aa, bb, cc, dd, ee, block[10], 14); + FF(ee, aa, bb, cc, dd, block[11], 15); + FF(dd, ee, aa, bb, cc, block[12], 6); + FF(cc, dd, ee, aa, bb, block[13], 7); + FF(bb, cc, dd, ee, aa, block[14], 9); + FF(aa, bb, cc, dd, ee, block[15], 8); + + /* round 2 */ + GG(ee, aa, bb, cc, dd, block[ 7], 7); + GG(dd, ee, aa, bb, cc, block[ 4], 6); + GG(cc, dd, ee, aa, bb, block[13], 8); + GG(bb, cc, dd, ee, aa, block[ 1], 13); + GG(aa, bb, cc, dd, ee, block[10], 11); + GG(ee, aa, bb, cc, dd, block[ 6], 9); + GG(dd, ee, aa, bb, cc, block[15], 7); + GG(cc, dd, ee, aa, bb, block[ 3], 15); + GG(bb, cc, dd, ee, aa, block[12], 7); + GG(aa, bb, cc, dd, ee, block[ 0], 12); + GG(ee, aa, bb, cc, dd, block[ 9], 15); + GG(dd, ee, aa, bb, cc, block[ 5], 9); + GG(cc, dd, ee, aa, bb, block[ 2], 11); + GG(bb, cc, dd, ee, aa, block[14], 7); + GG(aa, bb, cc, dd, ee, block[11], 13); + GG(ee, aa, bb, cc, dd, block[ 8], 12); + + /* round 3 */ + HH(dd, ee, aa, bb, cc, block[ 3], 11); + HH(cc, dd, ee, aa, bb, block[10], 13); + HH(bb, cc, dd, ee, aa, block[14], 6); + HH(aa, bb, cc, dd, ee, block[ 4], 7); + HH(ee, aa, bb, cc, dd, block[ 9], 14); + HH(dd, ee, aa, bb, cc, block[15], 9); + HH(cc, dd, ee, aa, bb, block[ 8], 13); + HH(bb, cc, dd, ee, aa, block[ 1], 15); + HH(aa, bb, cc, dd, ee, block[ 2], 14); + HH(ee, aa, bb, cc, dd, block[ 7], 8); + HH(dd, ee, aa, bb, cc, block[ 0], 13); + HH(cc, dd, ee, aa, bb, block[ 6], 6); + HH(bb, cc, dd, ee, aa, block[13], 5); + HH(aa, bb, cc, dd, ee, block[11], 12); + HH(ee, aa, bb, cc, dd, block[ 5], 7); + HH(dd, ee, aa, bb, cc, block[12], 5); + + /* round 4 */ + II(cc, dd, ee, aa, bb, block[ 1], 11); + II(bb, cc, dd, ee, aa, block[ 9], 12); + II(aa, bb, cc, dd, ee, block[11], 14); + II(ee, aa, bb, cc, dd, block[10], 15); + II(dd, ee, aa, bb, cc, block[ 0], 14); + II(cc, dd, ee, aa, bb, block[ 8], 15); + II(bb, cc, dd, ee, aa, block[12], 9); + II(aa, bb, cc, dd, ee, block[ 4], 8); + II(ee, aa, bb, cc, dd, block[13], 9); + II(dd, ee, aa, bb, cc, block[ 3], 14); + II(cc, dd, ee, aa, bb, block[ 7], 5); + II(bb, cc, dd, ee, aa, block[15], 6); + II(aa, bb, cc, dd, ee, block[14], 8); + II(ee, aa, bb, cc, dd, block[ 5], 6); + II(dd, ee, aa, bb, cc, block[ 6], 5); + II(cc, dd, ee, aa, bb, block[ 2], 12); + + /* round 5 */ + JJ(bb, cc, dd, ee, aa, block[ 4], 9); + JJ(aa, bb, cc, dd, ee, block[ 0], 15); + JJ(ee, aa, bb, cc, dd, block[ 5], 5); + JJ(dd, ee, aa, bb, cc, block[ 9], 11); + JJ(cc, dd, ee, aa, bb, block[ 7], 6); + JJ(bb, cc, dd, ee, aa, block[12], 8); + JJ(aa, bb, cc, dd, ee, block[ 2], 13); + JJ(ee, aa, bb, cc, dd, block[10], 12); + JJ(dd, ee, aa, bb, cc, block[14], 5); + JJ(cc, dd, ee, aa, bb, block[ 1], 12); + JJ(bb, cc, dd, ee, aa, block[ 3], 13); + JJ(aa, bb, cc, dd, ee, block[ 8], 14); + JJ(ee, aa, bb, cc, dd, block[11], 11); + JJ(dd, ee, aa, bb, cc, block[ 6], 8); + JJ(cc, dd, ee, aa, bb, block[15], 5); + JJ(bb, cc, dd, ee, aa, block[13], 6); + + /* parallel round 1 */ + JJJ(aaa, bbb, ccc, ddd, eee, block[ 5], 8); + JJJ(eee, aaa, bbb, ccc, ddd, block[14], 9); + JJJ(ddd, eee, aaa, bbb, ccc, block[ 7], 9); + JJJ(ccc, ddd, eee, aaa, bbb, block[ 0], 11); + JJJ(bbb, ccc, ddd, eee, aaa, block[ 9], 13); + JJJ(aaa, bbb, ccc, ddd, eee, block[ 2], 15); + JJJ(eee, aaa, bbb, ccc, ddd, block[11], 15); + JJJ(ddd, eee, aaa, bbb, ccc, block[ 4], 5); + JJJ(ccc, ddd, eee, aaa, bbb, block[13], 7); + JJJ(bbb, ccc, ddd, eee, aaa, block[ 6], 7); + JJJ(aaa, bbb, ccc, ddd, eee, block[15], 8); + JJJ(eee, aaa, bbb, ccc, ddd, block[ 8], 11); + JJJ(ddd, eee, aaa, bbb, ccc, block[ 1], 14); + JJJ(ccc, ddd, eee, aaa, bbb, block[10], 14); + JJJ(bbb, ccc, ddd, eee, aaa, block[ 3], 12); + JJJ(aaa, bbb, ccc, ddd, eee, block[12], 6); + + /* parallel round 2 */ + III(eee, aaa, bbb, ccc, ddd, block[ 6], 9); + III(ddd, eee, aaa, bbb, ccc, block[11], 13); + III(ccc, ddd, eee, aaa, bbb, block[ 3], 15); + III(bbb, ccc, ddd, eee, aaa, block[ 7], 7); + III(aaa, bbb, ccc, ddd, eee, block[ 0], 12); + III(eee, aaa, bbb, ccc, ddd, block[13], 8); + III(ddd, eee, aaa, bbb, ccc, block[ 5], 9); + III(ccc, ddd, eee, aaa, bbb, block[10], 11); + III(bbb, ccc, ddd, eee, aaa, block[14], 7); + III(aaa, bbb, ccc, ddd, eee, block[15], 7); + III(eee, aaa, bbb, ccc, ddd, block[ 8], 12); + III(ddd, eee, aaa, bbb, ccc, block[12], 7); + III(ccc, ddd, eee, aaa, bbb, block[ 4], 6); + III(bbb, ccc, ddd, eee, aaa, block[ 9], 15); + III(aaa, bbb, ccc, ddd, eee, block[ 1], 13); + III(eee, aaa, bbb, ccc, ddd, block[ 2], 11); + + /* parallel round 3 */ + HHH(ddd, eee, aaa, bbb, ccc, block[15], 9); + HHH(ccc, ddd, eee, aaa, bbb, block[ 5], 7); + HHH(bbb, ccc, ddd, eee, aaa, block[ 1], 15); + HHH(aaa, bbb, ccc, ddd, eee, block[ 3], 11); + HHH(eee, aaa, bbb, ccc, ddd, block[ 7], 8); + HHH(ddd, eee, aaa, bbb, ccc, block[14], 6); + HHH(ccc, ddd, eee, aaa, bbb, block[ 6], 6); + HHH(bbb, ccc, ddd, eee, aaa, block[ 9], 14); + HHH(aaa, bbb, ccc, ddd, eee, block[11], 12); + HHH(eee, aaa, bbb, ccc, ddd, block[ 8], 13); + HHH(ddd, eee, aaa, bbb, ccc, block[12], 5); + HHH(ccc, ddd, eee, aaa, bbb, block[ 2], 14); + HHH(bbb, ccc, ddd, eee, aaa, block[10], 13); + HHH(aaa, bbb, ccc, ddd, eee, block[ 0], 13); + HHH(eee, aaa, bbb, ccc, ddd, block[ 4], 7); + HHH(ddd, eee, aaa, bbb, ccc, block[13], 5); + + /* parallel round 4 */ + GGG(ccc, ddd, eee, aaa, bbb, block[ 8], 15); + GGG(bbb, ccc, ddd, eee, aaa, block[ 6], 5); + GGG(aaa, bbb, ccc, ddd, eee, block[ 4], 8); + GGG(eee, aaa, bbb, ccc, ddd, block[ 1], 11); + GGG(ddd, eee, aaa, bbb, ccc, block[ 3], 14); + GGG(ccc, ddd, eee, aaa, bbb, block[11], 14); + GGG(bbb, ccc, ddd, eee, aaa, block[15], 6); + GGG(aaa, bbb, ccc, ddd, eee, block[ 0], 14); + GGG(eee, aaa, bbb, ccc, ddd, block[ 5], 6); + GGG(ddd, eee, aaa, bbb, ccc, block[12], 9); + GGG(ccc, ddd, eee, aaa, bbb, block[ 2], 12); + GGG(bbb, ccc, ddd, eee, aaa, block[13], 9); + GGG(aaa, bbb, ccc, ddd, eee, block[ 9], 12); + GGG(eee, aaa, bbb, ccc, ddd, block[ 7], 5); + GGG(ddd, eee, aaa, bbb, ccc, block[10], 15); + GGG(ccc, ddd, eee, aaa, bbb, block[14], 8); + + /* parallel round 5 */ + FFF(bbb, ccc, ddd, eee, aaa, block[12] , 8); + FFF(aaa, bbb, ccc, ddd, eee, block[15] , 5); + FFF(eee, aaa, bbb, ccc, ddd, block[10] , 12); + FFF(ddd, eee, aaa, bbb, ccc, block[ 4] , 9); + FFF(ccc, ddd, eee, aaa, bbb, block[ 1] , 12); + FFF(bbb, ccc, ddd, eee, aaa, block[ 5] , 5); + FFF(aaa, bbb, ccc, ddd, eee, block[ 8] , 14); + FFF(eee, aaa, bbb, ccc, ddd, block[ 7] , 6); + FFF(ddd, eee, aaa, bbb, ccc, block[ 6] , 8); + FFF(ccc, ddd, eee, aaa, bbb, block[ 2] , 13); + FFF(bbb, ccc, ddd, eee, aaa, block[13] , 6); + FFF(aaa, bbb, ccc, ddd, eee, block[14] , 5); + FFF(eee, aaa, bbb, ccc, ddd, block[ 0] , 15); + FFF(ddd, eee, aaa, bbb, ccc, block[ 3] , 13); + FFF(ccc, ddd, eee, aaa, bbb, block[ 9] , 11); + FFF(bbb, ccc, ddd, eee, aaa, block[11] , 11); + + /* combine results */ + ddd += cc + state[1]; /* final result for state[0] */ + state[1] = state[2] + dd + eee; + state[2] = state[3] + ee + aaa; + state[3] = state[4] + aa + bbb; + state[4] = state[0] + bb + ccc; + state[0] = ddd; } /********************************************************************/ @@ -352,26 +352,26 @@ RMD160_Transform(uint32_t state[5], const uint32_t block[16]) void RMD160_Update(RMD160_CTX *context, const uint8_t *data, size_t nbytes) { - uint32_t X[16]; - uint32_t ofs = 0; - uint32_t i; + uint32_t X[16]; + uint32_t ofs = 0; + uint32_t i; #ifdef WORDS_BIGENDIAN - uint32_t j; + uint32_t j; #endif - _DIAGASSERT(context != NULL); - _DIAGASSERT(data != NULL); + _DIAGASSERT(context != NULL); + _DIAGASSERT(data != NULL); - /* update length[] */ + /* update length[] */ #if SIZEOF_SIZE_T * CHAR_BIT > 32 - context->length[1] += (uint32_t)((context->length[0] + nbytes) >> 32); + context->length[1] += (uint32_t)((context->length[0] + nbytes) >> 32); #else - if (context->length[0] + nbytes < context->length[0]) - context->length[1]++; /* overflow to msb of length */ + if (context->length[0] + nbytes < context->length[0]) + context->length[1]++; /* overflow to msb of length */ #endif - context->length[0] += (uint32_t)nbytes; + context->length[0] += (uint32_t)nbytes; - (void)memset(X, 0, sizeof(X)); + (void)memset(X, 0, sizeof(X)); if ( context->buflen + nbytes < 64 ) { @@ -416,48 +416,48 @@ RMD160_Update(RMD160_CTX *context, const uint8_t *data, size_t nbytes) int RMD160_Finish(RMD160_CTX *context, uint8_t digest[20]) { - uint32_t i; - uint32_t X[16]; + uint32_t i; + uint32_t X[16]; #ifdef WORDS_BIGENDIAN - uint32_t j; + uint32_t j; #endif - _DIAGASSERT(digest != NULL); - _DIAGASSERT(context != NULL); + _DIAGASSERT(digest != NULL); + _DIAGASSERT(context != NULL); - /* append the bit m_n == 1 */ - context->bbuffer[context->buflen] = (uint8_t)'\200'; + /* append the bit m_n == 1 */ + context->bbuffer[context->buflen] = (uint8_t)'\200'; - (void)memset(context->bbuffer + context->buflen + 1, 0, - 63 - context->buflen); + (void)memset(context->bbuffer + context->buflen + 1, 0, + 63 - context->buflen); #ifndef WORDS_BIGENDIAN - (void)memcpy(X, context->bbuffer, sizeof(X)); + (void)memcpy(X, context->bbuffer, sizeof(X)); #else - for (j=0; j < 16; j++) - X[j] = BYTES_TO_DWORD(context->bbuffer + (4 * j)); + for (j=0; j < 16; j++) + X[j] = BYTES_TO_DWORD(context->bbuffer + (4 * j)); #endif - if ((context->buflen) > 55) { - /* length goes to next block */ - RMD160_Transform(context->state, X); - (void)memset(X, 0, sizeof(X)); - } - - /* append length in bits */ - X[14] = context->length[0] << 3; - X[15] = (context->length[0] >> 29) | - (context->length[1] << 3); - RMD160_Transform(context->state, X); - - if (digest != NULL) { - for (i = 0; i < 20; i += 4) { - /* extracts the 8 least significant bits. */ - digest[i] = context->state[i>>2]; - digest[i + 1] = (context->state[i>>2] >> 8); - digest[i + 2] = (context->state[i>>2] >> 16); - digest[i + 3] = (context->state[i>>2] >> 24); - } - } - return 1; + if ((context->buflen) > 55) { + /* length goes to next block */ + RMD160_Transform(context->state, X); + (void)memset(X, 0, sizeof(X)); + } + + /* append length in bits */ + X[14] = context->length[0] << 3; + X[15] = (context->length[0] >> 29) | + (context->length[1] << 3); + RMD160_Transform(context->state, X); + + if (digest != NULL) { + for (i = 0; i < 20; i += 4) { + /* extracts the 8 least significant bits. */ + digest[i] = context->state[i>>2]; + digest[i + 1] = (context->state[i>>2] >> 8); + digest[i + 2] = (context->state[i>>2] >> 16); + digest[i + 3] = (context->state[i>>2] >> 24); + } + } + return 1; } /************************ end of file rmd160.c **********************/ diff --git a/ext/digest/rmd160/rmd160.h b/ext/digest/rmd160/rmd160.h index 617b262d906753..6324709d9602f2 100644 --- a/ext/digest/rmd160/rmd160.h +++ b/ext/digest/rmd160/rmd160.h @@ -29,10 +29,10 @@ #include "../defs.h" typedef struct { - uint32_t state[5]; /* state (ABCDE) */ - uint32_t length[2]; /* number of bits */ - uint8_t bbuffer[64]; /* overflow buffer */ - uint32_t buflen; /* number of chars in bbuffer */ + uint32_t state[5]; /* state (ABCDE) */ + uint32_t length[2]; /* number of bits */ + uint8_t bbuffer[64]; /* overflow buffer */ + uint32_t buflen; /* number of chars in bbuffer */ } RMD160_CTX; #ifdef RUBY diff --git a/ext/digest/sha1/sha1.c b/ext/digest/sha1/sha1.c index afe952f8ba8c52..53112275498795 100644 --- a/ext/digest/sha1/sha1.c +++ b/ext/digest/sha1/sha1.c @@ -227,16 +227,16 @@ void SHA1_Update(SHA1_CTX *context, const uint8_t *data, size_t len) j = context->count[0]; if ((context->count[0] += len << 3) < j) - context->count[1] += (len>>29)+1; + context->count[1] += (len>>29)+1; j = (j >> 3) & 63; if ((j + len) > 63) { - (void)memcpy(&context->buffer[j], data, (i = 64-j)); - SHA1_Transform(context->state, context->buffer); - for ( ; i + 63 < len; i += 64) - SHA1_Transform(context->state, &data[i]); - j = 0; + (void)memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1_Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) + SHA1_Transform(context->state, &data[i]); + j = 0; } else { - i = 0; + i = 0; } (void)memcpy(&context->buffer[j], &data[i], len - i); } @@ -254,18 +254,18 @@ int SHA1_Finish(SHA1_CTX* context, uint8_t digest[20]) _DIAGASSERT(context != 0); for (i = 0; i < 8; i++) { - finalcount[i] = (uint8_t)((context->count[(i >= 4 ? 0 : 1)] - >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + finalcount[i] = (uint8_t)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ } SHA1_Update(context, (const uint8_t *)"\200", 1); while ((context->count[0] & 504) != 448) - SHA1_Update(context, (const uint8_t *)"\0", 1); + SHA1_Update(context, (const uint8_t *)"\0", 1); SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */ if (digest) { - for (i = 0; i < 20; i++) - digest[i] = (uint8_t) - ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + for (i = 0; i < 20; i++) + digest[i] = (uint8_t) + ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); } return 1; } diff --git a/ext/digest/sha1/sha1.h b/ext/digest/sha1/sha1.h index e1d01b76ab14e0..2accc46d465d00 100644 --- a/ext/digest/sha1/sha1.h +++ b/ext/digest/sha1/sha1.h @@ -14,9 +14,9 @@ #include "../defs.h" typedef struct { - uint32_t state[5]; - uint32_t count[2]; - uint8_t buffer[64]; + uint32_t state[5]; + uint32_t count[2]; + uint8_t buffer[64]; } SHA1_CTX; #ifdef RUBY diff --git a/ext/digest/sha2/sha2.c b/ext/digest/sha2/sha2.c index 2a9dbd4fce0cb1..21d5acbe964287 100644 --- a/ext/digest/sha2/sha2.c +++ b/ext/digest/sha2/sha2.c @@ -136,17 +136,17 @@ typedef u_int64_t sha2_word64; /* Exactly 8 bytes */ /*** ENDIAN REVERSAL MACROS *******************************************/ #if BYTE_ORDER == LITTLE_ENDIAN #define REVERSE32(w,x) { \ - sha2_word32 tmp = (w); \ - tmp = (tmp >> 16) | (tmp << 16); \ - (x) = ((tmp & (sha2_word32)0xff00ff00UL) >> 8) | ((tmp & (sha2_word32)0x00ff00ffUL) << 8); \ + sha2_word32 tmp = (w); \ + tmp = (tmp >> 16) | (tmp << 16); \ + (x) = ((tmp & (sha2_word32)0xff00ff00UL) >> 8) | ((tmp & (sha2_word32)0x00ff00ffUL) << 8); \ } #define REVERSE64(w,x) { \ - sha2_word64 tmp = (w); \ - tmp = (tmp >> 32) | (tmp << 32); \ - tmp = ((tmp & ULL(0xff00ff00ff00ff00)) >> 8) | \ - ((tmp & ULL(0x00ff00ff00ff00ff)) << 8); \ - (x) = ((tmp & ULL(0xffff0000ffff0000)) >> 16) | \ - ((tmp & ULL(0x0000ffff0000ffff)) << 16); \ + sha2_word64 tmp = (w); \ + tmp = (tmp >> 32) | (tmp << 32); \ + tmp = ((tmp & ULL(0xff00ff00ff00ff00)) >> 8) | \ + ((tmp & ULL(0x00ff00ff00ff00ff)) << 8); \ + (x) = ((tmp & ULL(0xffff0000ffff0000)) >> 16) | \ + ((tmp & ULL(0x0000ffff0000ffff)) << 16); \ } #endif /* BYTE_ORDER == LITTLE_ENDIAN */ @@ -156,10 +156,10 @@ typedef u_int64_t sha2_word64; /* Exactly 8 bytes */ * 64-bit words): */ #define ADDINC128(w,n) { \ - (w)[0] += (sha2_word64)(n); \ - if ((w)[0] < (n)) { \ - (w)[1]++; \ - } \ + (w)[0] += (sha2_word64)(n); \ + if ((w)[0] < (n)) { \ + (w)[1]++; \ + } \ } /* @@ -235,102 +235,102 @@ void SHA512_Transform(SHA512_CTX*, const sha2_word64*); /*** SHA-XYZ INITIAL HASH VALUES AND CONSTANTS ************************/ /* Hash constant words K for SHA-256: */ static const sha2_word32 K256[64] = { - 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, - 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, - 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, - 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, - 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, - 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, - 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, - 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, - 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, - 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, - 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, - 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, - 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, - 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, - 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, - 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, + 0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, + 0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL, + 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL, + 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, + 0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, + 0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL, + 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL, + 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, + 0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, + 0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL, + 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL, + 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL }; /* Initial hash value H for SHA-256: */ static const sha2_word32 sha256_initial_hash_value[8] = { - 0x6a09e667UL, - 0xbb67ae85UL, - 0x3c6ef372UL, - 0xa54ff53aUL, - 0x510e527fUL, - 0x9b05688cUL, - 0x1f83d9abUL, - 0x5be0cd19UL + 0x6a09e667UL, + 0xbb67ae85UL, + 0x3c6ef372UL, + 0xa54ff53aUL, + 0x510e527fUL, + 0x9b05688cUL, + 0x1f83d9abUL, + 0x5be0cd19UL }; /* Hash constant words K for SHA-384 and SHA-512: */ static const sha2_word64 K512[80] = { - ULL(0x428a2f98d728ae22), ULL(0x7137449123ef65cd), - ULL(0xb5c0fbcfec4d3b2f), ULL(0xe9b5dba58189dbbc), - ULL(0x3956c25bf348b538), ULL(0x59f111f1b605d019), - ULL(0x923f82a4af194f9b), ULL(0xab1c5ed5da6d8118), - ULL(0xd807aa98a3030242), ULL(0x12835b0145706fbe), - ULL(0x243185be4ee4b28c), ULL(0x550c7dc3d5ffb4e2), - ULL(0x72be5d74f27b896f), ULL(0x80deb1fe3b1696b1), - ULL(0x9bdc06a725c71235), ULL(0xc19bf174cf692694), - ULL(0xe49b69c19ef14ad2), ULL(0xefbe4786384f25e3), - ULL(0x0fc19dc68b8cd5b5), ULL(0x240ca1cc77ac9c65), - ULL(0x2de92c6f592b0275), ULL(0x4a7484aa6ea6e483), - ULL(0x5cb0a9dcbd41fbd4), ULL(0x76f988da831153b5), - ULL(0x983e5152ee66dfab), ULL(0xa831c66d2db43210), - ULL(0xb00327c898fb213f), ULL(0xbf597fc7beef0ee4), - ULL(0xc6e00bf33da88fc2), ULL(0xd5a79147930aa725), - ULL(0x06ca6351e003826f), ULL(0x142929670a0e6e70), - ULL(0x27b70a8546d22ffc), ULL(0x2e1b21385c26c926), - ULL(0x4d2c6dfc5ac42aed), ULL(0x53380d139d95b3df), - ULL(0x650a73548baf63de), ULL(0x766a0abb3c77b2a8), - ULL(0x81c2c92e47edaee6), ULL(0x92722c851482353b), - ULL(0xa2bfe8a14cf10364), ULL(0xa81a664bbc423001), - ULL(0xc24b8b70d0f89791), ULL(0xc76c51a30654be30), - ULL(0xd192e819d6ef5218), ULL(0xd69906245565a910), - ULL(0xf40e35855771202a), ULL(0x106aa07032bbd1b8), - ULL(0x19a4c116b8d2d0c8), ULL(0x1e376c085141ab53), - ULL(0x2748774cdf8eeb99), ULL(0x34b0bcb5e19b48a8), - ULL(0x391c0cb3c5c95a63), ULL(0x4ed8aa4ae3418acb), - ULL(0x5b9cca4f7763e373), ULL(0x682e6ff3d6b2b8a3), - ULL(0x748f82ee5defb2fc), ULL(0x78a5636f43172f60), - ULL(0x84c87814a1f0ab72), ULL(0x8cc702081a6439ec), - ULL(0x90befffa23631e28), ULL(0xa4506cebde82bde9), - ULL(0xbef9a3f7b2c67915), ULL(0xc67178f2e372532b), - ULL(0xca273eceea26619c), ULL(0xd186b8c721c0c207), - ULL(0xeada7dd6cde0eb1e), ULL(0xf57d4f7fee6ed178), - ULL(0x06f067aa72176fba), ULL(0x0a637dc5a2c898a6), - ULL(0x113f9804bef90dae), ULL(0x1b710b35131c471b), - ULL(0x28db77f523047d84), ULL(0x32caab7b40c72493), - ULL(0x3c9ebe0a15c9bebc), ULL(0x431d67c49c100d4c), - ULL(0x4cc5d4becb3e42b6), ULL(0x597f299cfc657e2a), - ULL(0x5fcb6fab3ad6faec), ULL(0x6c44198c4a475817) + ULL(0x428a2f98d728ae22), ULL(0x7137449123ef65cd), + ULL(0xb5c0fbcfec4d3b2f), ULL(0xe9b5dba58189dbbc), + ULL(0x3956c25bf348b538), ULL(0x59f111f1b605d019), + ULL(0x923f82a4af194f9b), ULL(0xab1c5ed5da6d8118), + ULL(0xd807aa98a3030242), ULL(0x12835b0145706fbe), + ULL(0x243185be4ee4b28c), ULL(0x550c7dc3d5ffb4e2), + ULL(0x72be5d74f27b896f), ULL(0x80deb1fe3b1696b1), + ULL(0x9bdc06a725c71235), ULL(0xc19bf174cf692694), + ULL(0xe49b69c19ef14ad2), ULL(0xefbe4786384f25e3), + ULL(0x0fc19dc68b8cd5b5), ULL(0x240ca1cc77ac9c65), + ULL(0x2de92c6f592b0275), ULL(0x4a7484aa6ea6e483), + ULL(0x5cb0a9dcbd41fbd4), ULL(0x76f988da831153b5), + ULL(0x983e5152ee66dfab), ULL(0xa831c66d2db43210), + ULL(0xb00327c898fb213f), ULL(0xbf597fc7beef0ee4), + ULL(0xc6e00bf33da88fc2), ULL(0xd5a79147930aa725), + ULL(0x06ca6351e003826f), ULL(0x142929670a0e6e70), + ULL(0x27b70a8546d22ffc), ULL(0x2e1b21385c26c926), + ULL(0x4d2c6dfc5ac42aed), ULL(0x53380d139d95b3df), + ULL(0x650a73548baf63de), ULL(0x766a0abb3c77b2a8), + ULL(0x81c2c92e47edaee6), ULL(0x92722c851482353b), + ULL(0xa2bfe8a14cf10364), ULL(0xa81a664bbc423001), + ULL(0xc24b8b70d0f89791), ULL(0xc76c51a30654be30), + ULL(0xd192e819d6ef5218), ULL(0xd69906245565a910), + ULL(0xf40e35855771202a), ULL(0x106aa07032bbd1b8), + ULL(0x19a4c116b8d2d0c8), ULL(0x1e376c085141ab53), + ULL(0x2748774cdf8eeb99), ULL(0x34b0bcb5e19b48a8), + ULL(0x391c0cb3c5c95a63), ULL(0x4ed8aa4ae3418acb), + ULL(0x5b9cca4f7763e373), ULL(0x682e6ff3d6b2b8a3), + ULL(0x748f82ee5defb2fc), ULL(0x78a5636f43172f60), + ULL(0x84c87814a1f0ab72), ULL(0x8cc702081a6439ec), + ULL(0x90befffa23631e28), ULL(0xa4506cebde82bde9), + ULL(0xbef9a3f7b2c67915), ULL(0xc67178f2e372532b), + ULL(0xca273eceea26619c), ULL(0xd186b8c721c0c207), + ULL(0xeada7dd6cde0eb1e), ULL(0xf57d4f7fee6ed178), + ULL(0x06f067aa72176fba), ULL(0x0a637dc5a2c898a6), + ULL(0x113f9804bef90dae), ULL(0x1b710b35131c471b), + ULL(0x28db77f523047d84), ULL(0x32caab7b40c72493), + ULL(0x3c9ebe0a15c9bebc), ULL(0x431d67c49c100d4c), + ULL(0x4cc5d4becb3e42b6), ULL(0x597f299cfc657e2a), + ULL(0x5fcb6fab3ad6faec), ULL(0x6c44198c4a475817) }; /* Initial hash value H for SHA-384 */ static const sha2_word64 sha384_initial_hash_value[8] = { - ULL(0xcbbb9d5dc1059ed8), - ULL(0x629a292a367cd507), - ULL(0x9159015a3070dd17), - ULL(0x152fecd8f70e5939), - ULL(0x67332667ffc00b31), - ULL(0x8eb44a8768581511), - ULL(0xdb0c2e0d64f98fa7), - ULL(0x47b5481dbefa4fa4) + ULL(0xcbbb9d5dc1059ed8), + ULL(0x629a292a367cd507), + ULL(0x9159015a3070dd17), + ULL(0x152fecd8f70e5939), + ULL(0x67332667ffc00b31), + ULL(0x8eb44a8768581511), + ULL(0xdb0c2e0d64f98fa7), + ULL(0x47b5481dbefa4fa4) }; /* Initial hash value H for SHA-512 */ static const sha2_word64 sha512_initial_hash_value[8] = { - ULL(0x6a09e667f3bcc908), - ULL(0xbb67ae8584caa73b), - ULL(0x3c6ef372fe94f82b), - ULL(0xa54ff53a5f1d36f1), - ULL(0x510e527fade682d1), - ULL(0x9b05688c2b3e6c1f), - ULL(0x1f83d9abfb41bd6b), - ULL(0x5be0cd19137e2179) + ULL(0x6a09e667f3bcc908), + ULL(0xbb67ae8584caa73b), + ULL(0x3c6ef372fe94f82b), + ULL(0xa54ff53a5f1d36f1), + ULL(0x510e527fade682d1), + ULL(0x9b05688c2b3e6c1f), + ULL(0x1f83d9abfb41bd6b), + ULL(0x5be0cd19137e2179) }; /* @@ -342,13 +342,13 @@ static const char *sha2_hex_digits = "0123456789abcdef"; /*** SHA-256: *********************************************************/ int SHA256_Init(SHA256_CTX* context) { - if (context == (SHA256_CTX*)0) { - return 0; - } - MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH); - MEMSET_BZERO(context->buffer, SHA256_BLOCK_LENGTH); - context->bitcount = 0; - return 1; + if (context == (SHA256_CTX*)0) { + return 0; + } + MEMCPY_BCOPY(context->state, sha256_initial_hash_value, SHA256_DIGEST_LENGTH); + MEMSET_BZERO(context->buffer, SHA256_BLOCK_LENGTH); + context->bitcount = 0; + return 1; } #ifdef SHA2_UNROLL_TRANSFORM @@ -358,328 +358,328 @@ int SHA256_Init(SHA256_CTX* context) { #if BYTE_ORDER == LITTLE_ENDIAN #define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ - REVERSE32(*data++, W256[j]); \ - T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + REVERSE32(*data++, W256[j]); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ K256[j] + W256[j]; \ - (d) += T1; \ - (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ - j++ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ #else /* BYTE_ORDER == LITTLE_ENDIAN */ #define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ - T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ - K256[j] + (W256[j] = *data++); \ - (d) += T1; \ - (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ - j++ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ + K256[j] + (W256[j] = *data++); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ #endif /* BYTE_ORDER == LITTLE_ENDIAN */ #define ROUND256(a,b,c,d,e,f,g,h) \ - s0 = W256[(j+1)&0x0f]; \ - s0 = sigma0_256(s0); \ - s1 = W256[(j+14)&0x0f]; \ - s1 = sigma1_256(s1); \ - T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ - (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ - (d) += T1; \ - (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ - j++ + s0 = W256[(j+1)&0x0f]; \ + s0 = sigma0_256(s0); \ + s1 = W256[(j+14)&0x0f]; \ + s1 = sigma1_256(s1); \ + T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + K256[j] + \ + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); \ + (d) += T1; \ + (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ + j++ void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { - sha2_word32 a, b, c, d, e, f, g, h, s0, s1; - sha2_word32 T1, *W256; - int j; - - W256 = (sha2_word32*)context->buffer; - - /* Initialize registers with the prev. intermediate value */ - a = context->state[0]; - b = context->state[1]; - c = context->state[2]; - d = context->state[3]; - e = context->state[4]; - f = context->state[5]; - g = context->state[6]; - h = context->state[7]; - - j = 0; - do { - /* Rounds 0 to 15 (unrolled): */ - ROUND256_0_TO_15(a,b,c,d,e,f,g,h); - ROUND256_0_TO_15(h,a,b,c,d,e,f,g); - ROUND256_0_TO_15(g,h,a,b,c,d,e,f); - ROUND256_0_TO_15(f,g,h,a,b,c,d,e); - ROUND256_0_TO_15(e,f,g,h,a,b,c,d); - ROUND256_0_TO_15(d,e,f,g,h,a,b,c); - ROUND256_0_TO_15(c,d,e,f,g,h,a,b); - ROUND256_0_TO_15(b,c,d,e,f,g,h,a); - } while (j < 16); - - /* Now for the remaining rounds to 64: */ - do { - ROUND256(a,b,c,d,e,f,g,h); - ROUND256(h,a,b,c,d,e,f,g); - ROUND256(g,h,a,b,c,d,e,f); - ROUND256(f,g,h,a,b,c,d,e); - ROUND256(e,f,g,h,a,b,c,d); - ROUND256(d,e,f,g,h,a,b,c); - ROUND256(c,d,e,f,g,h,a,b); - ROUND256(b,c,d,e,f,g,h,a); - } while (j < 64); - - /* Compute the current intermediate hash value */ - context->state[0] += a; - context->state[1] += b; - context->state[2] += c; - context->state[3] += d; - context->state[4] += e; - context->state[5] += f; - context->state[6] += g; - context->state[7] += h; - - /* Clean up */ - a = b = c = d = e = f = g = h = T1 = 0; + sha2_word32 a, b, c, d, e, f, g, h, s0, s1; + sha2_word32 T1, *W256; + int j; + + W256 = (sha2_word32*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + /* Rounds 0 to 15 (unrolled): */ + ROUND256_0_TO_15(a,b,c,d,e,f,g,h); + ROUND256_0_TO_15(h,a,b,c,d,e,f,g); + ROUND256_0_TO_15(g,h,a,b,c,d,e,f); + ROUND256_0_TO_15(f,g,h,a,b,c,d,e); + ROUND256_0_TO_15(e,f,g,h,a,b,c,d); + ROUND256_0_TO_15(d,e,f,g,h,a,b,c); + ROUND256_0_TO_15(c,d,e,f,g,h,a,b); + ROUND256_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds to 64: */ + do { + ROUND256(a,b,c,d,e,f,g,h); + ROUND256(h,a,b,c,d,e,f,g); + ROUND256(g,h,a,b,c,d,e,f); + ROUND256(f,g,h,a,b,c,d,e); + ROUND256(e,f,g,h,a,b,c,d); + ROUND256(d,e,f,g,h,a,b,c); + ROUND256(c,d,e,f,g,h,a,b); + ROUND256(b,c,d,e,f,g,h,a); + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; } #else /* SHA2_UNROLL_TRANSFORM */ void SHA256_Transform(SHA256_CTX* context, const sha2_word32* data) { - sha2_word32 a, b, c, d, e, f, g, h, s0, s1; - sha2_word32 T1, T2, *W256; - int j; - - W256 = (sha2_word32*)context->buffer; - - /* Initialize registers with the prev. intermediate value */ - a = context->state[0]; - b = context->state[1]; - c = context->state[2]; - d = context->state[3]; - e = context->state[4]; - f = context->state[5]; - g = context->state[6]; - h = context->state[7]; - - j = 0; - do { + sha2_word32 a, b, c, d, e, f, g, h, s0, s1; + sha2_word32 T1, T2, *W256; + int j; + + W256 = (sha2_word32*)context->buffer; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { #if BYTE_ORDER == LITTLE_ENDIAN - /* Copy data while converting to host byte order */ - REVERSE32(*data++,W256[j]); - /* Apply the SHA-256 compression function to update a..h */ - T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; + /* Copy data while converting to host byte order */ + REVERSE32(*data++,W256[j]); + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + W256[j]; #else /* BYTE_ORDER == LITTLE_ENDIAN */ - /* Apply the SHA-256 compression function to update a..h with copy */ - T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); + /* Apply the SHA-256 compression function to update a..h with copy */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + (W256[j] = *data++); #endif /* BYTE_ORDER == LITTLE_ENDIAN */ - T2 = Sigma0_256(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - - j++; - } while (j < 16); - - do { - /* Part of the message block expansion: */ - s0 = W256[(j+1)&0x0f]; - s0 = sigma0_256(s0); - s1 = W256[(j+14)&0x0f]; - s1 = sigma1_256(s1); - - /* Apply the SHA-256 compression function to update a..h */ - T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + - (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); - T2 = Sigma0_256(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - - j++; - } while (j < 64); - - /* Compute the current intermediate hash value */ - context->state[0] += a; - context->state[1] += b; - context->state[2] += c; - context->state[3] += d; - context->state[4] += e; - context->state[5] += f; - context->state[6] += g; - context->state[7] += h; - - /* Clean up */ - a = b = c = d = e = f = g = h = T1 = T2 = 0; + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W256[(j+1)&0x0f]; + s0 = sigma0_256(s0); + s1 = W256[(j+14)&0x0f]; + s1 = sigma1_256(s1); + + /* Apply the SHA-256 compression function to update a..h */ + T1 = h + Sigma1_256(e) + Ch(e, f, g) + K256[j] + + (W256[j&0x0f] += s1 + W256[(j+9)&0x0f] + s0); + T2 = Sigma0_256(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 64); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; } #endif /* SHA2_UNROLL_TRANSFORM */ void SHA256_Update(SHA256_CTX* context, const sha2_byte *data, size_t len) { - unsigned int freespace, usedspace; - - if (len == 0) { - /* Calling with no data is valid - we do nothing */ - return; - } - - /* Sanity check: */ - assert(context != (SHA256_CTX*)0 && data != (sha2_byte*)0); - - usedspace = (unsigned int)((context->bitcount >> 3) % SHA256_BLOCK_LENGTH); - if (usedspace > 0) { - /* Calculate how much free space is available in the buffer */ - freespace = SHA256_BLOCK_LENGTH - usedspace; - - if (len >= freespace) { - /* Fill the buffer completely and process it */ - MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); - context->bitcount += freespace << 3; - len -= freespace; - data += freespace; - SHA256_Transform(context, (sha2_word32*)context->buffer); - } else { - /* The buffer is not yet full */ - MEMCPY_BCOPY(&context->buffer[usedspace], data, len); - context->bitcount += len << 3; - /* Clean up: */ - usedspace = freespace = 0; - return; - } - } - while (len >= SHA256_BLOCK_LENGTH) { - /* Process as many complete blocks as we can */ - MEMCPY_BCOPY(context->buffer, data, SHA256_BLOCK_LENGTH); - SHA256_Transform(context, (sha2_word32*)context->buffer); - context->bitcount += SHA256_BLOCK_LENGTH << 3; - len -= SHA256_BLOCK_LENGTH; - data += SHA256_BLOCK_LENGTH; - } - if (len > 0) { - /* There's left-overs, so save 'em */ - MEMCPY_BCOPY(context->buffer, data, len); - context->bitcount += len << 3; - } - /* Clean up: */ - usedspace = freespace = 0; + unsigned int freespace, usedspace; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + assert(context != (SHA256_CTX*)0 && data != (sha2_byte*)0); + + usedspace = (unsigned int)((context->bitcount >> 3) % SHA256_BLOCK_LENGTH); + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA256_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); + context->bitcount += freespace << 3; + len -= freespace; + data += freespace; + SHA256_Transform(context, (sha2_word32*)context->buffer); + } else { + /* The buffer is not yet full */ + MEMCPY_BCOPY(&context->buffer[usedspace], data, len); + context->bitcount += len << 3; + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA256_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + MEMCPY_BCOPY(context->buffer, data, SHA256_BLOCK_LENGTH); + SHA256_Transform(context, (sha2_word32*)context->buffer); + context->bitcount += SHA256_BLOCK_LENGTH << 3; + len -= SHA256_BLOCK_LENGTH; + data += SHA256_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + MEMCPY_BCOPY(context->buffer, data, len); + context->bitcount += len << 3; + } + /* Clean up: */ + usedspace = freespace = 0; } int SHA256_Final(sha2_byte digest[SHA256_DIGEST_LENGTH], SHA256_CTX* context) { - sha2_word32 *d = (sha2_word32*)digest; - unsigned int usedspace; + sha2_word32 *d = (sha2_word32*)digest; + unsigned int usedspace; - /* Sanity check: */ - assert(context != (SHA256_CTX*)0); + /* Sanity check: */ + assert(context != (SHA256_CTX*)0); - /* If no digest buffer is passed, we don't bother doing this: */ - if (digest != (sha2_byte*)0) { - usedspace = (unsigned int)((context->bitcount >> 3) % SHA256_BLOCK_LENGTH); + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + usedspace = (unsigned int)((context->bitcount >> 3) % SHA256_BLOCK_LENGTH); #if BYTE_ORDER == LITTLE_ENDIAN - /* Convert FROM host byte order */ - REVERSE64(context->bitcount,context->bitcount); + /* Convert FROM host byte order */ + REVERSE64(context->bitcount,context->bitcount); #endif - if (usedspace > 0) { - /* Begin padding with a 1 bit: */ - context->buffer[usedspace++] = 0x80; - - if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { - /* Set-up for the last transform: */ - MEMSET_BZERO(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace); - } else { - if (usedspace < SHA256_BLOCK_LENGTH) { - MEMSET_BZERO(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace); - } - /* Do second-to-last transform: */ - SHA256_Transform(context, (sha2_word32*)context->buffer); - - /* And set-up for the last transform: */ - MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); - } - } else { - /* Set-up for the last transform: */ - MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); - - /* Begin padding with a 1 bit: */ - *context->buffer = 0x80; - } - /* Set the bit count: */ - MEMCPY_BCOPY(&context->buffer[SHA256_SHORT_BLOCK_LENGTH], &context->bitcount, - sizeof(sha2_word64)); - - /* Final transform: */ - SHA256_Transform(context, (sha2_word32*)context->buffer); + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + MEMSET_BZERO(&context->buffer[usedspace], SHA256_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < SHA256_BLOCK_LENGTH) { + MEMSET_BZERO(&context->buffer[usedspace], SHA256_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + SHA256_Transform(context, (sha2_word32*)context->buffer); + + /* And set-up for the last transform: */ + MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + } + } else { + /* Set-up for the last transform: */ + MEMSET_BZERO(context->buffer, SHA256_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Set the bit count: */ + MEMCPY_BCOPY(&context->buffer[SHA256_SHORT_BLOCK_LENGTH], &context->bitcount, + sizeof(sha2_word64)); + + /* Final transform: */ + SHA256_Transform(context, (sha2_word32*)context->buffer); #if BYTE_ORDER == LITTLE_ENDIAN - { - /* Convert TO host byte order */ - int j; - for (j = 0; j < 8; j++) { - REVERSE32(context->state[j],context->state[j]); - *d++ = context->state[j]; - } - } + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE32(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } #else - MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH); + MEMCPY_BCOPY(d, context->state, SHA256_DIGEST_LENGTH); #endif - } + } - /* Clean up state data: */ - MEMSET_BZERO(context, sizeof(*context)); - usedspace = 0; - return 1; + /* Clean up state data: */ + MEMSET_BZERO(context, sizeof(*context)); + usedspace = 0; + return 1; } char *SHA256_End(SHA256_CTX* context, char buffer[SHA256_DIGEST_STRING_LENGTH]) { - sha2_byte digest[SHA256_DIGEST_LENGTH], *d = digest; - int i; - - /* Sanity check: */ - assert(context != (SHA256_CTX*)0); - - if (buffer != (char*)0) { - SHA256_Final(digest, context); - for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { - *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; - *buffer++ = sha2_hex_digits[*d & 0x0f]; - d++; - } - *buffer = (char)0; - } else { - MEMSET_BZERO(context, sizeof(*context)); - } - MEMSET_BZERO(digest, SHA256_DIGEST_LENGTH); - return buffer; + sha2_byte digest[SHA256_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA256_CTX*)0); + + if (buffer != (char*)0) { + SHA256_Final(digest, context); + for (i = 0; i < SHA256_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + MEMSET_BZERO(context, sizeof(*context)); + } + MEMSET_BZERO(digest, SHA256_DIGEST_LENGTH); + return buffer; } char* SHA256_Data(const sha2_byte* data, size_t len, char digest[SHA256_DIGEST_STRING_LENGTH]) { - SHA256_CTX context; + SHA256_CTX context; - SHA256_Init(&context); - SHA256_Update(&context, data, len); - return SHA256_End(&context, digest); + SHA256_Init(&context); + SHA256_Update(&context, data, len); + return SHA256_End(&context, digest); } /*** SHA-512: *********************************************************/ int SHA512_Init(SHA512_CTX* context) { - if (context == (SHA512_CTX*)0) { - return 0; - } - MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH); - MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH); - context->bitcount[0] = context->bitcount[1] = 0; - return 1; + if (context == (SHA512_CTX*)0) { + return 0; + } + MEMCPY_BCOPY(context->state, sha512_initial_hash_value, SHA512_DIGEST_LENGTH); + MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; + return 1; } #ifdef SHA2_UNROLL_TRANSFORM @@ -688,394 +688,394 @@ int SHA512_Init(SHA512_CTX* context) { #if BYTE_ORDER == LITTLE_ENDIAN #define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ - REVERSE64(*data++, W512[j]); \ - T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + REVERSE64(*data++, W512[j]); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ K512[j] + W512[j]; \ - (d) += T1, \ - (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \ - j++ + (d) += T1, \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)), \ + j++ #else /* BYTE_ORDER == LITTLE_ENDIAN */ #define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ - T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ K512[j] + (W512[j] = *data++); \ - (d) += T1; \ - (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ - j++ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ #endif /* BYTE_ORDER == LITTLE_ENDIAN */ #define ROUND512(a,b,c,d,e,f,g,h) \ - s0 = W512[(j+1)&0x0f]; \ - s0 = sigma0_512(s0); \ - s1 = W512[(j+14)&0x0f]; \ - s1 = sigma1_512(s1); \ - T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ + s0 = W512[(j+1)&0x0f]; \ + s0 = sigma0_512(s0); \ + s1 = W512[(j+14)&0x0f]; \ + s1 = sigma1_512(s1); \ + T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + K512[j] + \ (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); \ - (d) += T1; \ - (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ - j++ + (d) += T1; \ + (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ + j++ void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { - sha2_word64 a, b, c, d, e, f, g, h, s0, s1; - sha2_word64 T1, *W512 = (sha2_word64*)context->buffer; - int j; - - /* Initialize registers with the prev. intermediate value */ - a = context->state[0]; - b = context->state[1]; - c = context->state[2]; - d = context->state[3]; - e = context->state[4]; - f = context->state[5]; - g = context->state[6]; - h = context->state[7]; - - j = 0; - do { - ROUND512_0_TO_15(a,b,c,d,e,f,g,h); - ROUND512_0_TO_15(h,a,b,c,d,e,f,g); - ROUND512_0_TO_15(g,h,a,b,c,d,e,f); - ROUND512_0_TO_15(f,g,h,a,b,c,d,e); - ROUND512_0_TO_15(e,f,g,h,a,b,c,d); - ROUND512_0_TO_15(d,e,f,g,h,a,b,c); - ROUND512_0_TO_15(c,d,e,f,g,h,a,b); - ROUND512_0_TO_15(b,c,d,e,f,g,h,a); - } while (j < 16); - - /* Now for the remaining rounds up to 79: */ - do { - ROUND512(a,b,c,d,e,f,g,h); - ROUND512(h,a,b,c,d,e,f,g); - ROUND512(g,h,a,b,c,d,e,f); - ROUND512(f,g,h,a,b,c,d,e); - ROUND512(e,f,g,h,a,b,c,d); - ROUND512(d,e,f,g,h,a,b,c); - ROUND512(c,d,e,f,g,h,a,b); - ROUND512(b,c,d,e,f,g,h,a); - } while (j < 80); - - /* Compute the current intermediate hash value */ - context->state[0] += a; - context->state[1] += b; - context->state[2] += c; - context->state[3] += d; - context->state[4] += e; - context->state[5] += f; - context->state[6] += g; - context->state[7] += h; - - /* Clean up */ - a = b = c = d = e = f = g = h = T1 = 0; + sha2_word64 a, b, c, d, e, f, g, h, s0, s1; + sha2_word64 T1, *W512 = (sha2_word64*)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + ROUND512_0_TO_15(a,b,c,d,e,f,g,h); + ROUND512_0_TO_15(h,a,b,c,d,e,f,g); + ROUND512_0_TO_15(g,h,a,b,c,d,e,f); + ROUND512_0_TO_15(f,g,h,a,b,c,d,e); + ROUND512_0_TO_15(e,f,g,h,a,b,c,d); + ROUND512_0_TO_15(d,e,f,g,h,a,b,c); + ROUND512_0_TO_15(c,d,e,f,g,h,a,b); + ROUND512_0_TO_15(b,c,d,e,f,g,h,a); + } while (j < 16); + + /* Now for the remaining rounds up to 79: */ + do { + ROUND512(a,b,c,d,e,f,g,h); + ROUND512(h,a,b,c,d,e,f,g); + ROUND512(g,h,a,b,c,d,e,f); + ROUND512(f,g,h,a,b,c,d,e); + ROUND512(e,f,g,h,a,b,c,d); + ROUND512(d,e,f,g,h,a,b,c); + ROUND512(c,d,e,f,g,h,a,b); + ROUND512(b,c,d,e,f,g,h,a); + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = 0; } #else /* SHA2_UNROLL_TRANSFORM */ void SHA512_Transform(SHA512_CTX* context, const sha2_word64* data) { - sha2_word64 a, b, c, d, e, f, g, h, s0, s1; - sha2_word64 T1, T2, *W512 = (sha2_word64*)context->buffer; - int j; - - /* Initialize registers with the prev. intermediate value */ - a = context->state[0]; - b = context->state[1]; - c = context->state[2]; - d = context->state[3]; - e = context->state[4]; - f = context->state[5]; - g = context->state[6]; - h = context->state[7]; - - j = 0; - do { + sha2_word64 a, b, c, d, e, f, g, h, s0, s1; + sha2_word64 T1, T2, *W512 = (sha2_word64*)context->buffer; + int j; + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { #if BYTE_ORDER == LITTLE_ENDIAN - /* Convert TO host byte order */ - REVERSE64(*data++, W512[j]); - /* Apply the SHA-512 compression function to update a..h */ - T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; + /* Convert TO host byte order */ + REVERSE64(*data++, W512[j]); + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + W512[j]; #else /* BYTE_ORDER == LITTLE_ENDIAN */ - /* Apply the SHA-512 compression function to update a..h with copy */ - T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); + /* Apply the SHA-512 compression function to update a..h with copy */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + (W512[j] = *data++); #endif /* BYTE_ORDER == LITTLE_ENDIAN */ - T2 = Sigma0_512(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - - j++; - } while (j < 16); - - do { - /* Part of the message block expansion: */ - s0 = W512[(j+1)&0x0f]; - s0 = sigma0_512(s0); - s1 = W512[(j+14)&0x0f]; - s1 = sigma1_512(s1); - - /* Apply the SHA-512 compression function to update a..h */ - T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + - (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); - T2 = Sigma0_512(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - - j++; - } while (j < 80); - - /* Compute the current intermediate hash value */ - context->state[0] += a; - context->state[1] += b; - context->state[2] += c; - context->state[3] += d; - context->state[4] += e; - context->state[5] += f; - context->state[6] += g; - context->state[7] += h; - - /* Clean up */ - a = b = c = d = e = f = g = h = T1 = T2 = 0; + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W512[(j+1)&0x0f]; + s0 = sigma0_512(s0); + s1 = W512[(j+14)&0x0f]; + s1 = sigma1_512(s1); + + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512[j] + + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; } #endif /* SHA2_UNROLL_TRANSFORM */ void SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { - unsigned int freespace, usedspace; - - if (len == 0) { - /* Calling with no data is valid - we do nothing */ - return; - } - - /* Sanity check: */ - assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0); - - usedspace = (unsigned int)((context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH); - if (usedspace > 0) { - /* Calculate how much free space is available in the buffer */ - freespace = SHA512_BLOCK_LENGTH - usedspace; - - if (len >= freespace) { - /* Fill the buffer completely and process it */ - MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); - ADDINC128(context->bitcount, freespace << 3); - len -= freespace; - data += freespace; - SHA512_Transform(context, (sha2_word64*)context->buffer); - } else { - /* The buffer is not yet full */ - MEMCPY_BCOPY(&context->buffer[usedspace], data, len); - ADDINC128(context->bitcount, len << 3); - /* Clean up: */ - usedspace = freespace = 0; - return; - } - } - while (len >= SHA512_BLOCK_LENGTH) { - /* Process as many complete blocks as we can */ - MEMCPY_BCOPY(context->buffer, data, SHA512_BLOCK_LENGTH); - SHA512_Transform(context, (sha2_word64*)context->buffer); - ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); - len -= SHA512_BLOCK_LENGTH; - data += SHA512_BLOCK_LENGTH; - } - if (len > 0) { - /* There's left-overs, so save 'em */ - MEMCPY_BCOPY(context->buffer, data, len); - ADDINC128(context->bitcount, len << 3); - } - /* Clean up: */ - usedspace = freespace = 0; + unsigned int freespace, usedspace; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0); + + usedspace = (unsigned int)((context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH); + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA512_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + MEMCPY_BCOPY(&context->buffer[usedspace], data, freespace); + ADDINC128(context->bitcount, freespace << 3); + len -= freespace; + data += freespace; + SHA512_Transform(context, (sha2_word64*)context->buffer); + } else { + /* The buffer is not yet full */ + MEMCPY_BCOPY(&context->buffer[usedspace], data, len); + ADDINC128(context->bitcount, len << 3); + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA512_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + MEMCPY_BCOPY(context->buffer, data, SHA512_BLOCK_LENGTH); + SHA512_Transform(context, (sha2_word64*)context->buffer); + ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); + len -= SHA512_BLOCK_LENGTH; + data += SHA512_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + MEMCPY_BCOPY(context->buffer, data, len); + ADDINC128(context->bitcount, len << 3); + } + /* Clean up: */ + usedspace = freespace = 0; } void SHA512_Last(SHA512_CTX* context) { - unsigned int usedspace; + unsigned int usedspace; - usedspace = (unsigned int)((context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH); + usedspace = (unsigned int)((context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH); #if BYTE_ORDER == LITTLE_ENDIAN - /* Convert FROM host byte order */ - REVERSE64(context->bitcount[0],context->bitcount[0]); - REVERSE64(context->bitcount[1],context->bitcount[1]); + /* Convert FROM host byte order */ + REVERSE64(context->bitcount[0],context->bitcount[0]); + REVERSE64(context->bitcount[1],context->bitcount[1]); #endif - if (usedspace > 0) { - /* Begin padding with a 1 bit: */ - context->buffer[usedspace++] = 0x80; - - if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { - /* Set-up for the last transform: */ - MEMSET_BZERO(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace); - } else { - if (usedspace < SHA512_BLOCK_LENGTH) { - MEMSET_BZERO(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); - } - /* Do second-to-last transform: */ - SHA512_Transform(context, (sha2_word64*)context->buffer); - - /* And set-up for the last transform: */ - MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2); - } - } else { - /* Prepare for final transform: */ - MEMSET_BZERO(context->buffer, SHA512_SHORT_BLOCK_LENGTH); - - /* Begin padding with a 1 bit: */ - *context->buffer = 0x80; - } - /* Store the length of input data (in bits): */ - MEMCPY_BCOPY(&context->buffer[SHA512_SHORT_BLOCK_LENGTH], &context->bitcount[1], - sizeof(sha2_word64)); - MEMCPY_BCOPY(&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8], &context->bitcount[0], - sizeof(sha2_word64)); - - /* Final transform: */ - SHA512_Transform(context, (sha2_word64*)context->buffer); + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + + if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + MEMSET_BZERO(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < SHA512_BLOCK_LENGTH) { + MEMSET_BZERO(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + SHA512_Transform(context, (sha2_word64*)context->buffer); + + /* And set-up for the last transform: */ + MEMSET_BZERO(context->buffer, SHA512_BLOCK_LENGTH - 2); + } + } else { + /* Prepare for final transform: */ + MEMSET_BZERO(context->buffer, SHA512_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Store the length of input data (in bits): */ + MEMCPY_BCOPY(&context->buffer[SHA512_SHORT_BLOCK_LENGTH], &context->bitcount[1], + sizeof(sha2_word64)); + MEMCPY_BCOPY(&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8], &context->bitcount[0], + sizeof(sha2_word64)); + + /* Final transform: */ + SHA512_Transform(context, (sha2_word64*)context->buffer); } int SHA512_Final(sha2_byte digest[SHA512_DIGEST_LENGTH], SHA512_CTX* context) { - sha2_word64 *d = (sha2_word64*)digest; + sha2_word64 *d = (sha2_word64*)digest; - /* Sanity check: */ - assert(context != (SHA512_CTX*)0); + /* Sanity check: */ + assert(context != (SHA512_CTX*)0); - /* If no digest buffer is passed, we don't bother doing this: */ - if (digest != (sha2_byte*)0) { - SHA512_Last(context); + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + SHA512_Last(context); - /* Save the hash data for output: */ + /* Save the hash data for output: */ #if BYTE_ORDER == LITTLE_ENDIAN - { - /* Convert TO host byte order */ - int j; - for (j = 0; j < 8; j++) { - REVERSE64(context->state[j],context->state[j]); - *d++ = context->state[j]; - } - } + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 8; j++) { + REVERSE64(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } #else - MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH); + MEMCPY_BCOPY(d, context->state, SHA512_DIGEST_LENGTH); #endif - } + } - /* Zero out state data */ - MEMSET_BZERO(context, sizeof(*context)); - return 1; + /* Zero out state data */ + MEMSET_BZERO(context, sizeof(*context)); + return 1; } char *SHA512_End(SHA512_CTX* context, char buffer[SHA512_DIGEST_STRING_LENGTH]) { - sha2_byte digest[SHA512_DIGEST_LENGTH], *d = digest; - int i; - - /* Sanity check: */ - assert(context != (SHA512_CTX*)0); - - if (buffer != (char*)0) { - SHA512_Final(digest, context); - for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { - *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; - *buffer++ = sha2_hex_digits[*d & 0x0f]; - d++; - } - *buffer = (char)0; - } else { - MEMSET_BZERO(context, sizeof(*context)); - } - MEMSET_BZERO(digest, SHA512_DIGEST_LENGTH); - return buffer; + sha2_byte digest[SHA512_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA512_CTX*)0); + + if (buffer != (char*)0) { + SHA512_Final(digest, context); + for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + MEMSET_BZERO(context, sizeof(*context)); + } + MEMSET_BZERO(digest, SHA512_DIGEST_LENGTH); + return buffer; } char* SHA512_Data(const sha2_byte* data, size_t len, char digest[SHA512_DIGEST_STRING_LENGTH]) { - SHA512_CTX context; + SHA512_CTX context; - SHA512_Init(&context); - SHA512_Update(&context, data, len); - return SHA512_End(&context, digest); + SHA512_Init(&context); + SHA512_Update(&context, data, len); + return SHA512_End(&context, digest); } /*** SHA-384: *********************************************************/ int SHA384_Init(SHA384_CTX* context) { - if (context == (SHA384_CTX*)0) { - return 0; - } - MEMCPY_BCOPY(context->state, sha384_initial_hash_value, SHA512_DIGEST_LENGTH); - MEMSET_BZERO(context->buffer, SHA384_BLOCK_LENGTH); - context->bitcount[0] = context->bitcount[1] = 0; - return 1; + if (context == (SHA384_CTX*)0) { + return 0; + } + MEMCPY_BCOPY(context->state, sha384_initial_hash_value, SHA512_DIGEST_LENGTH); + MEMSET_BZERO(context->buffer, SHA384_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; + return 1; } void SHA384_Update(SHA384_CTX* context, const sha2_byte* data, size_t len) { - SHA512_Update((SHA512_CTX*)context, data, len); + SHA512_Update((SHA512_CTX*)context, data, len); } int SHA384_Final(sha2_byte digest[SHA384_DIGEST_LENGTH], SHA384_CTX* context) { - sha2_word64 *d = (sha2_word64*)digest; + sha2_word64 *d = (sha2_word64*)digest; - /* Sanity check: */ - assert(context != (SHA384_CTX*)0); + /* Sanity check: */ + assert(context != (SHA384_CTX*)0); - /* If no digest buffer is passed, we don't bother doing this: */ - if (digest != (sha2_byte*)0) { - SHA512_Last((SHA512_CTX*)context); + /* If no digest buffer is passed, we don't bother doing this: */ + if (digest != (sha2_byte*)0) { + SHA512_Last((SHA512_CTX*)context); - /* Save the hash data for output: */ + /* Save the hash data for output: */ #if BYTE_ORDER == LITTLE_ENDIAN - { - /* Convert TO host byte order */ - int j; - for (j = 0; j < 6; j++) { - REVERSE64(context->state[j],context->state[j]); - *d++ = context->state[j]; - } - } + { + /* Convert TO host byte order */ + int j; + for (j = 0; j < 6; j++) { + REVERSE64(context->state[j],context->state[j]); + *d++ = context->state[j]; + } + } #else - MEMCPY_BCOPY(d, context->state, SHA384_DIGEST_LENGTH); + MEMCPY_BCOPY(d, context->state, SHA384_DIGEST_LENGTH); #endif - } + } - /* Zero out state data */ - MEMSET_BZERO(context, sizeof(*context)); - return 1; + /* Zero out state data */ + MEMSET_BZERO(context, sizeof(*context)); + return 1; } char *SHA384_End(SHA384_CTX* context, char buffer[SHA384_DIGEST_STRING_LENGTH]) { - sha2_byte digest[SHA384_DIGEST_LENGTH], *d = digest; - int i; - - /* Sanity check: */ - assert(context != (SHA384_CTX*)0); - - if (buffer != (char*)0) { - SHA384_Final(digest, context); - for (i = 0; i < SHA384_DIGEST_LENGTH; i++) { - *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; - *buffer++ = sha2_hex_digits[*d & 0x0f]; - d++; - } - *buffer = (char)0; - } else { - MEMSET_BZERO(context, sizeof(*context)); - } - MEMSET_BZERO(digest, SHA384_DIGEST_LENGTH); - return buffer; + sha2_byte digest[SHA384_DIGEST_LENGTH], *d = digest; + int i; + + /* Sanity check: */ + assert(context != (SHA384_CTX*)0); + + if (buffer != (char*)0) { + SHA384_Final(digest, context); + for (i = 0; i < SHA384_DIGEST_LENGTH; i++) { + *buffer++ = sha2_hex_digits[(*d & 0xf0) >> 4]; + *buffer++ = sha2_hex_digits[*d & 0x0f]; + d++; + } + *buffer = (char)0; + } else { + MEMSET_BZERO(context, sizeof(*context)); + } + MEMSET_BZERO(digest, SHA384_DIGEST_LENGTH); + return buffer; } char* SHA384_Data(const sha2_byte* data, size_t len, char digest[SHA384_DIGEST_STRING_LENGTH]) { - SHA384_CTX context; + SHA384_CTX context; - SHA384_Init(&context); - SHA384_Update(&context, data, len); - return SHA384_End(&context, digest); + SHA384_Init(&context); + SHA384_Update(&context, data, len); + return SHA384_End(&context, digest); } diff --git a/ext/digest/sha2/sha2.h b/ext/digest/sha2/sha2.h index c2a29b99ad5273..e58f15ae1297bd 100644 --- a/ext/digest/sha2/sha2.h +++ b/ext/digest/sha2/sha2.h @@ -120,14 +120,14 @@ typedef unsigned long long uint64_t; /* 8-bytes (64-bits) */ * cc -DSHA2_USE_INTTYPES_H ... */ typedef struct _SHA256_CTX { - uint32_t state[8]; - uint64_t bitcount; - uint8_t buffer[SHA256_BLOCK_LENGTH]; + uint32_t state[8]; + uint64_t bitcount; + uint8_t buffer[SHA256_BLOCK_LENGTH]; } SHA256_CTX; typedef struct _SHA512_CTX { - uint64_t state[8]; - uint64_t bitcount[2]; - uint8_t buffer[SHA512_BLOCK_LENGTH]; + uint64_t state[8]; + uint64_t bitcount[2]; + uint8_t buffer[SHA512_BLOCK_LENGTH]; } SHA512_CTX; typedef SHA512_CTX SHA384_CTX; diff --git a/ext/extmk.rb b/ext/extmk.rb index b5ff735cc45f88..1624ec9099eb40 100755 --- a/ext/extmk.rb +++ b/ext/extmk.rb @@ -412,8 +412,10 @@ def $mflags.defined?(var) $ruby = $mflags.defined?("MINIRUBY") || CONFIG['MINIRUBY'] elsif sep = config_string('BUILD_FILE_SEPARATOR') $ruby = "$(topdir:/=#{sep})#{sep}miniruby" + EXEEXT -else +elsif CONFIG['EXTSTATIC'] $ruby = '$(topdir)/miniruby' + EXEEXT +else + $ruby = '$(topdir)/ruby' + EXEEXT end $ruby = [$ruby] $ruby << "-I'$(topdir)'" @@ -425,6 +427,7 @@ def $mflags.defined?(var) topruby = $ruby $ruby = topruby.join(' ') $mflags << "ruby=#$ruby" +$builtruby = '$(topdir)/miniruby' + EXEEXT # Must be an executable path MTIMES = [__FILE__, 'rbconfig.rb', srcdir+'/lib/mkmf.rb'].collect {|f| File.mtime(f)} diff --git a/ext/fiddle/closure.c b/ext/fiddle/closure.c index 3679e5c9adf090..a74cc53b78938d 100644 --- a/ext/fiddle/closure.c +++ b/ext/fiddle/closure.c @@ -74,7 +74,7 @@ with_gvl_callback(void *ptr) VALUE rbargs = rb_iv_get(self, "@args"); VALUE ctype = rb_iv_get(self, "@ctype"); int argc = RARRAY_LENINT(rbargs); - VALUE params = rb_ary_tmp_new(argc); + VALUE params = rb_ary_hidden_new(argc); VALUE ret; VALUE cPointer; int i, type; diff --git a/ext/io/nonblock/nonblock.c b/ext/io/nonblock/nonblock.c index cbd43d993a60ff..b8a40ff38e94a2 100644 --- a/ext/io/nonblock/nonblock.c +++ b/ext/io/nonblock/nonblock.c @@ -42,7 +42,7 @@ rb_io_nonblock_p(VALUE io) rb_io_t *fptr; GetOpenFile(io, fptr); if (get_fcntl_flags(fptr->fd) & O_NONBLOCK) - return Qtrue; + return Qtrue; return Qfalse; } #else @@ -54,21 +54,21 @@ static void set_fcntl_flags(int fd, int f) { if (fcntl(fd, F_SETFL, f) == -1) - rb_sys_fail(0); + rb_sys_fail(0); } static int io_nonblock_set(int fd, int f, int nb) { if (nb) { - if ((f & O_NONBLOCK) != 0) - return 0; - f |= O_NONBLOCK; + if ((f & O_NONBLOCK) != 0) + return 0; + f |= O_NONBLOCK; } else { - if ((f & O_NONBLOCK) == 0) - return 0; - f &= ~O_NONBLOCK; + if ((f & O_NONBLOCK) == 0) + return 0; + f &= ~O_NONBLOCK; } set_fcntl_flags(fd, f); return 1; @@ -127,9 +127,9 @@ rb_io_nonblock_set(VALUE io, VALUE nb) rb_io_t *fptr; GetOpenFile(io, fptr); if (RTEST(nb)) - rb_io_set_nonblock(fptr); + rb_io_set_nonblock(fptr); else - io_nonblock_set(fptr->fd, get_fcntl_flags(fptr->fd), RTEST(nb)); + io_nonblock_set(fptr->fd, get_fcntl_flags(fptr->fd), RTEST(nb)); return io; } @@ -160,15 +160,15 @@ rb_io_nonblock_block(int argc, VALUE *argv, VALUE io) GetOpenFile(io, fptr); if (argc > 0) { - VALUE v; - rb_scan_args(argc, argv, "01", &v); - nb = RTEST(v); + VALUE v; + rb_scan_args(argc, argv, "01", &v); + nb = RTEST(v); } f = get_fcntl_flags(fptr->fd); restore[0] = fptr->fd; restore[1] = f; if (!io_nonblock_set(fptr->fd, f, nb)) - return rb_yield(io); + return rb_yield(io); return rb_ensure(rb_yield, io, io_nonblock_restore, (VALUE)restore); } #else diff --git a/ext/json/generator/generator.c b/ext/json/generator/generator.c index e3a83472e113fc..98d0ea46c385dd 100644 --- a/ext/json/generator/generator.c +++ b/ext/json/generator/generator.c @@ -997,10 +997,10 @@ static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_St if (!allow_nan) { if (isinf(value)) { fbuffer_free(buffer); - rb_raise(eGeneratorError, "%u: %"PRIsVALUE" not allowed in JSON", __LINE__, RB_OBJ_STRING(tmp)); + rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", RB_OBJ_STRING(tmp)); } else if (isnan(value)) { fbuffer_free(buffer); - rb_raise(eGeneratorError, "%u: %"PRIsVALUE" not allowed in JSON", __LINE__, RB_OBJ_STRING(tmp)); + rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", RB_OBJ_STRING(tmp)); } } fbuffer_append_str(buffer, tmp); diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c index 8b860c4101c47f..9bd7f1971ef460 100644 --- a/ext/json/parser/parser.c +++ b/ext/json/parser/parser.c @@ -948,7 +948,7 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul {p = p - 1; } {p+= 1; cs = 29; goto _out;} } else { - rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p); + rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p); } } np = JSON_parse_float(json, p, pe, result); @@ -990,7 +990,7 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul if (json->allow_nan) { *result = CInfinity; } else { - rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p - 8); + rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 8); } } @@ -1002,7 +1002,7 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul if (json->allow_nan) { *result = CNaN; } else { - rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p - 2); + rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 2); } } @@ -2348,7 +2348,7 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul if(cs >= JSON_array_first_final) { return p + 1; } else { - rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p); + rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p); return NULL; } } @@ -2413,7 +2413,7 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int } rb_enc_raise( EXC_ENCODING eParserError, - "%u: incomplete unicode character escape sequence at '%s'", __LINE__, p + "incomplete unicode character escape sequence at '%s'", p ); } else { UTF32 ch = unescape_unicode((unsigned char *) ++pe); @@ -2426,7 +2426,7 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int } rb_enc_raise( EXC_ENCODING eParserError, - "%u: incomplete surrogate pair at '%s'", __LINE__, p + "incomplete surrogate pair at '%s'", p ); } if (pe[0] == '\\' && pe[1] == 'u') { @@ -3225,7 +3225,7 @@ static VALUE cParser_parse(VALUE self) if (cs >= JSON_first_final && p == pe) { return result; } else { - rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p); + rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p); return Qnil; } } diff --git a/ext/json/parser/parser.rl b/ext/json/parser/parser.rl index 2dee80ee3b8ea0..2dbdc7ef245170 100644 --- a/ext/json/parser/parser.rl +++ b/ext/json/parser/parser.rl @@ -222,14 +222,14 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu if (json->allow_nan) { *result = CNaN; } else { - rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p - 2); + rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 2); } } action parse_infinity { if (json->allow_nan) { *result = CInfinity; } else { - rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p - 8); + rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 8); } } action parse_string { @@ -245,7 +245,7 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu fexec p + 10; fhold; fbreak; } else { - rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p); + rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p); } } np = JSON_parse_float(json, fpc, pe, result); @@ -447,7 +447,7 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul if(cs >= JSON_array_first_final) { return p + 1; } else { - rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p); + rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p); return NULL; } } @@ -512,7 +512,7 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int } rb_enc_raise( EXC_ENCODING eParserError, - "%u: incomplete unicode character escape sequence at '%s'", __LINE__, p + "incomplete unicode character escape sequence at '%s'", p ); } else { UTF32 ch = unescape_unicode((unsigned char *) ++pe); @@ -525,7 +525,7 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int } rb_enc_raise( EXC_ENCODING eParserError, - "%u: incomplete surrogate pair at '%s'", __LINE__, p + "incomplete surrogate pair at '%s'", p ); } if (pe[0] == '\\' && pe[1] == 'u') { @@ -864,7 +864,7 @@ static VALUE cParser_parse(VALUE self) if (cs >= JSON_first_final && p == pe) { return result; } else { - rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p); + rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p); return Qnil; } } diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c index dee215447dacd5..08972e92a135cb 100644 --- a/ext/openssl/ossl_pkey_ec.c +++ b/ext/openssl/ossl_pkey_ec.c @@ -1462,7 +1462,7 @@ static VALUE ossl_ec_point_mul(int argc, VALUE *argv, VALUE self) "use #mul(bn) form instead"); num = RARRAY_LEN(arg1); - bns_tmp = rb_ary_tmp_new(num); + bns_tmp = rb_ary_hidden_new(num); bignums = ALLOCV_N(const BIGNUM *, tmp_b, num); for (i = 0; i < num; i++) { VALUE item = RARRAY_AREF(arg1, i); diff --git a/ext/pathname/lib/pathname.rb b/ext/pathname/lib/pathname.rb index 41e5c171a729ac..9a297529ca64e9 100644 --- a/ext/pathname/lib/pathname.rb +++ b/ext/pathname/lib/pathname.rb @@ -574,9 +574,9 @@ def find(ignore_error: true) # :yield: pathname end -class Pathname # * FileUtils * - autoload(:FileUtils, 'fileutils') +autoload(:FileUtils, 'fileutils') +class Pathname # * FileUtils * # Creates a full path, including any intermediate directories that don't yet # exist. # diff --git a/gc.c b/gc.c index 808b8e53993db9..df4c99b15b2cce 100644 --- a/gc.c +++ b/gc.c @@ -958,6 +958,24 @@ struct heap_page { bits_t pinned_bits[HEAP_PAGE_BITMAP_LIMIT]; }; +/* + * When asan is enabled, this will prohibit writing to the freelist until it is unlocked + */ +static void +asan_lock_freelist(struct heap_page *page) +{ + asan_poison_memory_region(&page->freelist, sizeof(RVALUE*)); +} + +/* + * When asan is enabled, this will enable the ability to write to the freelist + */ +static void +asan_unlock_freelist(struct heap_page *page) +{ + asan_unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false); +} + #define GET_PAGE_BODY(x) ((struct heap_page_body *)((bits_t)(x) & ~(HEAP_PAGE_ALIGN_MASK))) #define GET_PAGE_HEADER(x) (&GET_PAGE_BODY(x)->header) #define GET_HEAP_PAGE(x) (GET_PAGE_HEADER(x)->page) @@ -1939,12 +1957,12 @@ heap_page_add_freeobj(rb_objspace_t *objspace, struct heap_page *page, VALUE obj asan_unpoison_object(obj, false); - asan_unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false); + asan_unlock_freelist(page); p->as.free.flags = 0; p->as.free.next = page->freelist; page->freelist = p; - asan_poison_memory_region(&page->freelist, sizeof(RVALUE*)); + asan_lock_freelist(page); if (RGENGC_CHECK_MODE && /* obj should belong to page */ @@ -1961,7 +1979,7 @@ heap_page_add_freeobj(rb_objspace_t *objspace, struct heap_page *page, VALUE obj static inline void heap_add_freepage(rb_heap_t *heap, struct heap_page *page) { - asan_unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false); + asan_unlock_freelist(page); GC_ASSERT(page->free_slots != 0); GC_ASSERT(page->freelist != NULL); @@ -1970,14 +1988,14 @@ heap_add_freepage(rb_heap_t *heap, struct heap_page *page) RUBY_DEBUG_LOG("page:%p freelist:%p", (void *)page, (void *)page->freelist); - asan_poison_memory_region(&page->freelist, sizeof(RVALUE*)); + asan_lock_freelist(page); } #if GC_ENABLE_INCREMENTAL_MARK static inline void heap_add_poolpage(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *page) { - asan_unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false); + asan_unlock_freelist(page); GC_ASSERT(page->free_slots != 0); GC_ASSERT(page->freelist != NULL); @@ -1985,7 +2003,7 @@ heap_add_poolpage(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *pa heap->pooled_pages = page; objspace->rincgc.pooled_slots += page->free_slots; - asan_poison_memory_region(&page->freelist, sizeof(RVALUE*)); + asan_lock_freelist(page); } #endif @@ -2209,7 +2227,7 @@ heap_page_allocate(rb_objspace_t *objspace, rb_size_pool_t *size_pool) } page->free_slots = limit; - asan_poison_memory_region(&page->freelist, sizeof(RVALUE*)); + asan_lock_freelist(page); return page; } @@ -2219,10 +2237,10 @@ heap_page_resurrect(rb_objspace_t *objspace, rb_size_pool_t *size_pool) struct heap_page *page = 0, *next; ccan_list_for_each_safe(&SIZE_POOL_TOMB_HEAP(size_pool)->pages, page, next, page_node) { - asan_unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false); + asan_unlock_freelist(page); if (page->freelist != NULL) { heap_unlink_page(objspace, &size_pool->tomb_heap, page); - asan_poison_memory_region(&page->freelist, sizeof(RVALUE*)); + asan_lock_freelist(page); return page; } } @@ -2618,7 +2636,7 @@ heap_next_free_page(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_ GC_ASSERT(page->free_slots != 0); RUBY_DEBUG_LOG("page:%p freelist:%p cnt:%d", (void *)page, (void *)page->freelist, page->free_slots); - asan_unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false); + asan_unlock_freelist(page); return page; } @@ -5659,13 +5677,13 @@ gc_sweep_page(rb_objspace_t *objspace, rb_heap_t *heap, struct gc_sweep_context #if RGENGC_CHECK_MODE short freelist_len = 0; - asan_unpoison_memory_region(&sweep_page->freelist, sizeof(RVALUE*), false); + asan_unlock_freelist(sweep_page); RVALUE *ptr = sweep_page->freelist; while (ptr) { freelist_len++; ptr = ptr->as.free.next; } - asan_poison_memory_region(&sweep_page->freelist, sizeof(RVALUE*)); + asan_lock_freelist(sweep_page); if (freelist_len != sweep_page->free_slots) { rb_bug("inconsistent freelist length: expected %d but was %d", sweep_page->free_slots, freelist_len); } @@ -5723,7 +5741,7 @@ static void heap_page_freelist_append(struct heap_page *page, RVALUE *freelist) { if (freelist) { - asan_unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false); + asan_unlock_freelist(page); if (page->freelist) { RVALUE *p = page->freelist; asan_unpoison_object((VALUE)p, false); @@ -5739,7 +5757,7 @@ heap_page_freelist_append(struct heap_page *page, RVALUE *freelist) else { page->freelist = freelist; } - asan_poison_memory_region(&page->freelist, sizeof(RVALUE*)); + asan_lock_freelist(page); } } @@ -7934,7 +7952,7 @@ gc_verify_heap_pages_(rb_objspace_t *objspace, struct ccan_list_head *head) struct heap_page *page = 0; ccan_list_for_each(head, page, page_node) { - asan_unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false); + asan_unlock_freelist(page); RVALUE *p = page->freelist; while (p) { VALUE vp = (VALUE)p; @@ -7946,7 +7964,7 @@ gc_verify_heap_pages_(rb_objspace_t *objspace, struct ccan_list_head *head) p = p->as.free.next; asan_poison_object(prev); } - asan_poison_memory_region(&page->freelist, sizeof(RVALUE*)); + asan_lock_freelist(page); if (page->flags.has_remembered_objects == FALSE) { remembered_old_objects += gc_verify_heap_page(objspace, page, Qfalse); @@ -8434,7 +8452,8 @@ gc_compact_move(rb_objspace_t *objspace, rb_heap_t *heap, rb_size_pool_t *size_p } static bool -gc_compact_plane(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap, uintptr_t p, bits_t bitset, struct heap_page *page) { +gc_compact_plane(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap, uintptr_t p, bits_t bitset, struct heap_page *page) +{ short slot_size = page->slot_size; short slot_bits = slot_size / BASE_SLOT_SIZE; GC_ASSERT(slot_bits > 0); @@ -8493,7 +8512,8 @@ gc_compact_page(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *h } static bool -gc_compact_all_compacted_p(rb_objspace_t *objspace) { +gc_compact_all_compacted_p(rb_objspace_t *objspace) +{ for (int i = 0; i < SIZE_POOL_COUNT; i++) { rb_size_pool_t *size_pool = &size_pools[i]; rb_heap_t *heap = SIZE_POOL_EDEN_HEAP(size_pool); @@ -8944,25 +8964,29 @@ rb_gc_writebarrier_unprotect(VALUE obj) gc_report(2, objspace, "rb_gc_writebarrier_unprotect: %s %s\n", obj_info(obj), rgengc_remembered(objspace, obj) ? " (already remembered)" : ""); - if (RVALUE_OLD_P(obj)) { - gc_report(1, objspace, "rb_gc_writebarrier_unprotect: %s\n", obj_info(obj)); - RVALUE_DEMOTE(objspace, obj); - gc_mark_set(objspace, obj); - gc_remember_unprotected(objspace, obj); + RB_VM_LOCK_ENTER_NO_BARRIER(); + { + if (RVALUE_OLD_P(obj)) { + gc_report(1, objspace, "rb_gc_writebarrier_unprotect: %s\n", obj_info(obj)); + RVALUE_DEMOTE(objspace, obj); + gc_mark_set(objspace, obj); + gc_remember_unprotected(objspace, obj); #if RGENGC_PROFILE - objspace->profile.total_shade_operation_count++; + objspace->profile.total_shade_operation_count++; #if RGENGC_PROFILE >= 2 - objspace->profile.shade_operation_count_types[BUILTIN_TYPE(obj)]++; + objspace->profile.shade_operation_count_types[BUILTIN_TYPE(obj)]++; #endif /* RGENGC_PROFILE >= 2 */ #endif /* RGENGC_PROFILE */ - } - else { - RVALUE_AGE_RESET(obj); - } + } + else { + RVALUE_AGE_RESET(obj); + } - RB_DEBUG_COUNTER_INC(obj_wb_unprotect); - MARK_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(obj), obj); + RB_DEBUG_COUNTER_INC(obj_wb_unprotect); + MARK_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(obj), obj); + } + RB_VM_LOCK_LEAVE_NO_BARRIER(); } } @@ -9135,7 +9159,7 @@ rb_gc_register_mark_object(VALUE obj) VALUE ary = rb_ary_last(0, 0, ary_ary); if (NIL_P(ary) || RARRAY_LEN(ary) >= MARK_OBJECT_ARY_BUCKET_SIZE) { - ary = rb_ary_tmp_new(MARK_OBJECT_ARY_BUCKET_SIZE); + ary = rb_ary_hidden_new(MARK_OBJECT_ARY_BUCKET_SIZE); rb_ary_push(ary_ary, ary); } @@ -9937,16 +9961,40 @@ gc_sort_heap_by_empty_slots(rb_objspace_t *objspace) static void gc_ref_update_array(rb_objspace_t * objspace, VALUE v) { - long i, len; + if (ARY_SHARED_P(v)) { +#if USE_RVARGC + VALUE old_root = RARRAY(v)->as.heap.aux.shared_root; +#endif - if (ARY_SHARED_P(v)) return; + UPDATE_IF_MOVED(objspace, RARRAY(v)->as.heap.aux.shared_root); - len = RARRAY_LEN(v); - if (len > 0) { - VALUE *ptr = (VALUE *)RARRAY_CONST_PTR_TRANSIENT(v); - for (i = 0; i < len; i++) { - UPDATE_IF_MOVED(objspace, ptr[i]); +#if USE_RVARGC + VALUE new_root = RARRAY(v)->as.heap.aux.shared_root; + // If the root is embedded and its location has changed + if (ARY_EMBED_P(new_root) && new_root != old_root) { + size_t offset = (size_t)(RARRAY(v)->as.heap.ptr - RARRAY(old_root)->as.ary); + GC_ASSERT(RARRAY(v)->as.heap.ptr >= RARRAY(old_root)->as.ary); + RARRAY(v)->as.heap.ptr = RARRAY(new_root)->as.ary + offset; } +#endif + } + else { + long len = RARRAY_LEN(v); + + if (len > 0) { + VALUE *ptr = (VALUE *)RARRAY_CONST_PTR_TRANSIENT(v); + for (long i = 0; i < len; i++) { + UPDATE_IF_MOVED(objspace, ptr[i]); + } + } + +#if USE_RVARGC + if ((size_t)GET_HEAP_PAGE(v)->slot_size >= rb_ary_size_as_embedded(v)) { + if (rb_ary_embeddable_p(v)) { + rb_ary_make_embedded(v); + } + } +#endif } } @@ -10446,19 +10494,7 @@ gc_update_object_references(rb_objspace_t *objspace, VALUE obj) return; case T_ARRAY: - if (ARY_SHARED_P(obj)) { - UPDATE_IF_MOVED(objspace, any->as.array.as.heap.aux.shared_root); - } - else { - gc_ref_update_array(objspace, obj); - } -#if USE_RVARGC - if ((size_t)GET_HEAP_PAGE(obj)->slot_size >= rb_ary_size_as_embedded(obj)) { - if (rb_ary_embeddable_p(obj)) { - rb_ary_make_embedded(obj); - } - } -#endif + gc_ref_update_array(objspace, obj); break; case T_HASH: @@ -10582,8 +10618,8 @@ static int gc_ref_update(void *vstart, void *vend, size_t stride, rb_objspace_t * objspace, struct heap_page *page) { VALUE v = (VALUE)vstart; - asan_unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false); - asan_poison_memory_region(&page->freelist, sizeof(RVALUE*)); + asan_unlock_freelist(page); + asan_lock_freelist(page); page->flags.has_uncollectible_shady_objects = FALSE; page->flags.has_remembered_objects = FALSE; @@ -12348,6 +12384,7 @@ objspace_xfree(rb_objspace_t *objspace, void *ptr, size_t old_size) objspace_malloc_increase(objspace, ptr, 0, old_size, MEMOP_TYPE_FREE) { free(ptr); + ptr = NULL; RB_DEBUG_COUNTER_INC(heap_xfree); } } @@ -14193,7 +14230,7 @@ rb_gcdebug_add_stress_to_class(int argc, VALUE *argv, VALUE self) rb_objspace_t *objspace = &rb_objspace; if (!stress_to_class) { - stress_to_class = rb_ary_tmp_new(argc); + stress_to_class = rb_ary_hidden_new(argc); } rb_ary_cat(stress_to_class, argv, argc); return self; diff --git a/gems/bundled_gems b/gems/bundled_gems index ebe195f78f4605..4bf063abff3b34 100644 --- a/gems/bundled_gems +++ b/gems/bundled_gems @@ -2,9 +2,9 @@ minitest 5.16.2 https://github.com/seattlerb/minitest power_assert 2.0.1 https://github.com/ruby/power_assert rake 13.0.6 https://github.com/ruby/rake -test-unit 3.5.3 https://github.com/test-unit/test-unit 3.5.3 +test-unit 3.5.3 https://github.com/test-unit/test-unit rexml 3.2.5 https://github.com/ruby/rexml -rss 0.2.9 https://github.com/ruby/rss 0.2.9 +rss 0.2.9 https://github.com/ruby/rss net-ftp 0.1.3 https://github.com/ruby/net-ftp net-imap 0.2.3 https://github.com/ruby/net-imap net-pop 0.1.1 https://github.com/ruby/net-pop diff --git a/hash.c b/hash.c index 989bef455c6985..8c20791ede41fd 100644 --- a/hash.c +++ b/hash.c @@ -3294,7 +3294,7 @@ rb_hash_transform_keys_bang(int argc, VALUE *argv, VALUE hash) if (!RHASH_TABLE_EMPTY_P(hash)) { long i; VALUE new_keys = hash_alloc(0); - VALUE pairs = rb_ary_tmp_new(RHASH_SIZE(hash) * 2); + VALUE pairs = rb_ary_hidden_new(RHASH_SIZE(hash) * 2); rb_hash_foreach(hash, flatten_i, pairs); for (i = 0; i < RARRAY_LEN(pairs); i += 2) { VALUE key = RARRAY_AREF(pairs, i), new_key, val; @@ -6639,31 +6639,26 @@ env_update(int argc, VALUE *argv, VALUE env) return env; } +NORETURN(static VALUE env_clone(int, VALUE *, VALUE)); /* * call-seq: - * ENV.clone(freeze: nil) -> ENV + * ENV.clone(freeze: nil) # raises TypeError * - * Returns ENV itself, and warns because ENV is a wrapper for the - * process-wide environment variables and a clone is useless. - * If +freeze+ keyword is given and not +nil+ or +false+, raises ArgumentError. - * If +freeze+ keyword is given and +true+, raises TypeError, as ENV storage - * cannot be frozen. + * Raises TypeError, because ENV is a wrapper for the process-wide + * environment variables and a clone is useless. + * Use #to_h to get a copy of ENV data as a hash. */ static VALUE env_clone(int argc, VALUE *argv, VALUE obj) { if (argc) { - VALUE opt, kwfreeze; + VALUE opt; if (rb_scan_args(argc, argv, "0:", &opt) < argc) { - kwfreeze = rb_get_freeze_opt(1, &opt); - if (RTEST(kwfreeze)) { - rb_raise(rb_eTypeError, "cannot freeze ENV"); - } + rb_get_freeze_opt(1, &opt); } } - rb_warn_deprecated("ENV.clone", "ENV.to_h"); - return envtbl; + rb_raise(rb_eTypeError, "Cannot clone ENV, use ENV.to_h to get a copy of ENV as a hash"); } NORETURN(static VALUE env_dup(VALUE)); diff --git a/hrtime.h b/hrtime.h index 4ac3d5472361a8..80aff5deb36b4d 100644 --- a/hrtime.h +++ b/hrtime.h @@ -36,6 +36,7 @@ #define RB_HRTIME_PER_MSEC (RB_HRTIME_PER_USEC * (rb_hrtime_t)1000) #define RB_HRTIME_PER_SEC (RB_HRTIME_PER_MSEC * (rb_hrtime_t)1000) #define RB_HRTIME_MAX UINT64_MAX +#define RB_HRTIME_MIN ((rb_hrtime_t)0) /* * Lets try to support time travelers. Lets assume anybody with a time machine @@ -91,6 +92,15 @@ rb_hrtime_add(rb_hrtime_t a, rb_hrtime_t b) return c; } +static inline rb_hrtime_t +rb_hrtime_sub(rb_hrtime_t a, rb_hrtime_t b) +{ + if (a < b) { + return RB_HRTIME_MIN; + } + return a - b; +} + /* * convert a timeval struct to rb_hrtime_t, clamping at RB_HRTIME_MAX */ diff --git a/include/ruby/fiber/scheduler.h b/include/ruby/fiber/scheduler.h index ced092adbcd3a1..9f67bd5bf6d194 100644 --- a/include/ruby/fiber/scheduler.h +++ b/include/ruby/fiber/scheduler.h @@ -43,10 +43,12 @@ struct timeval; * @return A `VALUE` which contains the result and/or errno. */ static inline VALUE -rb_fiber_scheduler_io_result(ssize_t result, int error) { +rb_fiber_scheduler_io_result(ssize_t result, int error) +{ if (result == -1) { return RB_INT2NUM(-error); - } else { + } + else { return RB_SIZE2NUM(result); } } @@ -63,11 +65,13 @@ rb_fiber_scheduler_io_result(ssize_t result, int error) { * @return The original result of the system call. */ static inline ssize_t -rb_fiber_scheduler_io_result_apply(VALUE result) { +rb_fiber_scheduler_io_result_apply(VALUE result) +{ if (RB_FIXNUM_P(result) && RB_NUM2INT(result) < 0) { errno = -RB_NUM2INT(result); return -1; - } else { + } + else { return RB_NUM2SIZE(result); } } diff --git a/include/ruby/internal/intern/array.h b/include/ruby/internal/intern/array.h index 17964bf810e82d..2262c6f0c621b1 100644 --- a/include/ruby/internal/intern/array.h +++ b/include/ruby/internal/intern/array.h @@ -107,14 +107,14 @@ VALUE rb_ary_new_from_args(long n, ...); VALUE rb_ary_new_from_values(long n, const VALUE *elts); /** - * Allocates a "temporary" array. This is a hidden empty array. Handy on - * occasions. + * Allocates a hidden (no class) empty array. * * @param[in] capa Designed capacity of the array. * @return A hidden, empty array. * @see rb_obj_hide() */ -VALUE rb_ary_tmp_new(long capa); +VALUE rb_ary_hidden_new(long capa); +#define rb_ary_tmp_new rb_ary_hidden_new /** * Destroys the given array for no reason. diff --git a/inits.c b/inits.c index f41e88d8387bc5..22ba6d5a8c33c0 100644 --- a/inits.c +++ b/inits.c @@ -98,6 +98,7 @@ rb_call_builtin_inits(void) BUILTIN(array); BUILTIN(kernel); BUILTIN(timev); + BUILTIN(thread_sync); BUILTIN(yjit); BUILTIN(nilclass); BUILTIN(marshal); diff --git a/internal/array.h b/internal/array.h index 0de82d9f3026b0..17d91a800ba71a 100644 --- a/internal/array.h +++ b/internal/array.h @@ -26,7 +26,7 @@ VALUE rb_ary_last(int, const VALUE *, VALUE); void rb_ary_set_len(VALUE, long); void rb_ary_delete_same(VALUE, VALUE); -VALUE rb_ary_tmp_new_fill(long capa); +VALUE rb_ary_hidden_new_fill(long capa); VALUE rb_ary_at(VALUE, VALUE); size_t rb_ary_memsize(VALUE); VALUE rb_to_array_type(VALUE obj); diff --git a/internal/imemo.h b/internal/imemo.h index 53d82eb20f8b9a..91b524e0a6ae77 100644 --- a/internal/imemo.h +++ b/internal/imemo.h @@ -10,7 +10,7 @@ */ #include "ruby/internal/config.h" #include /* for size_t */ -#include "internal/array.h" /* for rb_ary_tmp_new_fill */ +#include "internal/array.h" /* for rb_ary_hidden_new_fill */ #include "internal/gc.h" /* for RB_OBJ_WRITE */ #include "ruby/internal/stdbool.h" /* for bool */ #include "ruby/ruby.h" /* for rb_block_call_func_t */ @@ -121,9 +121,9 @@ struct MEMO { #define MEMO_NEW(a, b, c) ((struct MEMO *)rb_imemo_new(imemo_memo, (VALUE)(a), (VALUE)(b), (VALUE)(c), 0)) #define MEMO_FOR(type, value) ((type *)RARRAY_PTR(value)) #define NEW_MEMO_FOR(type, value) \ - ((value) = rb_ary_tmp_new_fill(type_roomof(type, VALUE)), MEMO_FOR(type, value)) + ((value) = rb_ary_hidden_new_fill(type_roomof(type, VALUE)), MEMO_FOR(type, value)) #define NEW_PARTIAL_MEMO_FOR(type, value, member) \ - ((value) = rb_ary_tmp_new_fill(type_roomof(type, VALUE)), \ + ((value) = rb_ary_hidden_new_fill(type_roomof(type, VALUE)), \ rb_ary_set_len((value), offsetof(type, member) / sizeof(VALUE)), \ MEMO_FOR(type, value)) diff --git a/internal/variable.h b/internal/variable.h index 4b67bef9078556..1a19e8964b9f8e 100644 --- a/internal/variable.h +++ b/internal/variable.h @@ -16,7 +16,7 @@ /* global variable */ -#define ROBJECT_TRANSIENT_FLAG FL_USER13 +#define ROBJECT_TRANSIENT_FLAG FL_USER2 /* variable.c */ void rb_gc_mark_global_tbl(void); diff --git a/io.c b/io.c index 34ccf249777c9b..1fe927895779f1 100644 --- a/io.c +++ b/io.c @@ -1224,7 +1224,8 @@ io_flush_buffer(rb_io_t *fptr) { if (!NIL_P(fptr->write_lock) && rb_mutex_owned_p(fptr->write_lock)) { return (int)io_flush_buffer_async((VALUE)fptr); - } else { + } + else { return (int)rb_mutex_synchronize(fptr->write_lock, io_flush_buffer_async, (VALUE)fptr); } } @@ -1699,7 +1700,8 @@ io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync) else { return io_binwrite_string((VALUE)&arg); } - } else { + } + else { if (fptr->wbuf.off) { if (fptr->wbuf.len) MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len); @@ -9569,11 +9571,11 @@ argf_initialize_copy(VALUE argf, VALUE orig) * call-seq: * ARGF.lineno = integer -> integer * - * Sets the line number of +ARGF+ as a whole to the given +Integer+. + * Sets the line number of ARGF as a whole to the given Integer. * - * +ARGF+ sets the line number automatically as you read data, so normally + * ARGF sets the line number automatically as you read data, so normally * you will not need to set it explicitly. To access the current line number - * use +ARGF.lineno+. + * use ARGF.lineno. * * For example: * @@ -9596,7 +9598,7 @@ argf_set_lineno(VALUE argf, VALUE val) * ARGF.lineno -> integer * * Returns the current line number of ARGF as a whole. This value - * can be set manually with +ARGF.lineno=+. + * can be set manually with ARGF.lineno=. * * For example: * @@ -9921,10 +9923,10 @@ rb_f_gets(int argc, VALUE *argv, VALUE recv) * ARGF.gets(limit [, getline_args]) -> string or nil * ARGF.gets(sep, limit [, getline_args]) -> string or nil * - * Returns the next line from the current file in +ARGF+. + * Returns the next line from the current file in ARGF. * * By default lines are assumed to be separated by $/; - * to use a different character as a separator, supply it as a +String+ + * to use a different character as a separator, supply it as a String * for the _sep_ argument. * * The optional _limit_ argument specifies how many characters of each line @@ -10003,16 +10005,16 @@ rb_f_readline(int argc, VALUE *argv, VALUE recv) * ARGF.readline(limit) -> string * ARGF.readline(sep, limit) -> string * - * Returns the next line from the current file in +ARGF+. + * Returns the next line from the current file in ARGF. * * By default lines are assumed to be separated by $/; - * to use a different character as a separator, supply it as a +String+ + * to use a different character as a separator, supply it as a String * for the _sep_ argument. * * The optional _limit_ argument specifies how many characters of each line * to return. By default all characters are returned. * - * An +EOFError+ is raised at the end of the file. + * An EOFError is raised at the end of the file. */ static VALUE argf_readline(int argc, VALUE *argv, VALUE argf) @@ -10109,7 +10111,7 @@ rb_f_readlines(int argc, VALUE *argv, VALUE recv) * ARGF.to_a(limit) -> array * ARGF.to_a(sep, limit) -> array * - * Reads each file in +ARGF+ in its entirety, returning an +Array+ containing + * Reads each file in ARGF in its entirety, returning an Array containing * lines from the files. Lines are assumed to be separated by _sep_. * * lines = ARGF.readlines @@ -13124,12 +13126,12 @@ global_argf_p(VALUE arg) * call-seq: * ARGF.external_encoding -> encoding * - * Returns the external encoding for files read from +ARGF+ as an +Encoding+ + * Returns the external encoding for files read from ARGF as an Encoding * object. The external encoding is the encoding of the text as stored in a - * file. Contrast with +ARGF.internal_encoding+, which is the encoding used - * to represent this text within Ruby. + * file. Contrast with ARGF.internal_encoding, which is the encoding used to + * represent this text within Ruby. * - * To set the external encoding use +ARGF.set_encoding+. + * To set the external encoding use ARGF.set_encoding. * * For example: * @@ -13149,10 +13151,10 @@ argf_external_encoding(VALUE argf) * call-seq: * ARGF.internal_encoding -> encoding * - * Returns the internal encoding for strings read from +ARGF+ as an - * +Encoding+ object. + * Returns the internal encoding for strings read from ARGF as an + * Encoding object. * - * If +ARGF.set_encoding+ has been called with two encoding names, the second + * If ARGF.set_encoding has been called with two encoding names, the second * is returned. Otherwise, if +Encoding.default_external+ has been set, that * value is returned. Failing that, if a default external encoding was * specified on the command-line, that value is used. If the encoding is @@ -13188,7 +13190,7 @@ argf_internal_encoding(VALUE argf) * specifies the internal encoding. * * If the external encoding and the internal encoding are specified, the - * optional +Hash+ argument can be used to adjust the conversion process. The + * optional Hash argument can be used to adjust the conversion process. The * structure of this hash is explained in the String#encode documentation. * * For example: @@ -13217,7 +13219,7 @@ argf_set_encoding(int argc, VALUE *argv, VALUE argf) * ARGF.tell -> Integer * ARGF.pos -> Integer * - * Returns the current offset (in bytes) of the current file in +ARGF+. + * Returns the current offset (in bytes) of the current file in ARGF. * * ARGF.pos #=> 0 * ARGF.gets #=> "This is line one\n" @@ -13238,7 +13240,7 @@ argf_tell(VALUE argf) * call-seq: * ARGF.seek(amount, whence=IO::SEEK_SET) -> 0 * - * Seeks to offset _amount_ (an +Integer+) in the +ARGF+ stream according to + * Seeks to offset _amount_ (an Integer) in the ARGF stream according to * the value of _whence_. See IO#seek for further details. */ static VALUE @@ -13255,7 +13257,7 @@ argf_seek_m(int argc, VALUE *argv, VALUE argf) * call-seq: * ARGF.pos = position -> Integer * - * Seeks to the position given by _position_ (in bytes) in +ARGF+. + * Seeks to the position given by _position_ (in bytes) in ARGF. * * For example: * @@ -13277,7 +13279,7 @@ argf_set_pos(VALUE argf, VALUE offset) * ARGF.rewind -> 0 * * Positions the current file to the beginning of input, resetting - * +ARGF.lineno+ to zero. + * ARGF.lineno to zero. * * ARGF.readline #=> "This is line one\n" * ARGF.rewind #=> 0 @@ -13308,7 +13310,7 @@ argf_rewind(VALUE argf) * ARGF.to_i -> integer * * Returns an integer representing the numeric file descriptor for - * the current file. Raises an +ArgumentError+ if there isn't a current file. + * the current file. Raises an ArgumentError if there isn't a current file. * * ARGF.fileno #=> 3 */ @@ -13326,8 +13328,8 @@ argf_fileno(VALUE argf) * call-seq: * ARGF.to_io -> IO * - * Returns an +IO+ object representing the current file. This will be a - * +File+ object unless the current file is a stream such as STDIN. + * Returns an IO object representing the current file. This will be a + * File object unless the current file is a stream such as STDIN. * * For example: * @@ -13347,8 +13349,8 @@ argf_to_io(VALUE argf) * ARGF.eof? -> true or false * ARGF.eof -> true or false * - * Returns true if the current file in +ARGF+ is at end of file, i.e. it has - * no data to read. The stream must be opened for reading or an +IOError+ + * Returns true if the current file in ARGF is at end of file, i.e. it has + * no data to read. The stream must be opened for reading or an IOError * will be raised. * * $ echo "eof" | ruby argf.rb @@ -13583,10 +13585,10 @@ argf_getpartial(int argc, VALUE *argv, VALUE argf, VALUE opts, int nonblock) * call-seq: * ARGF.getc -> String or nil * - * Reads the next character from +ARGF+ and returns it as a +String+. Returns + * Reads the next character from ARGF and returns it as a String. Returns * +nil+ at the end of the stream. * - * +ARGF+ treats the files named on the command line as a single file created + * ARGF treats the files named on the command line as a single file created * by concatenating their contents. After returning the last character of the * first file, it returns the first character of the second file, and so on. * @@ -13628,7 +13630,7 @@ argf_getc(VALUE argf) * call-seq: * ARGF.getbyte -> Integer or nil * - * Gets the next 8-bit byte (0..255) from +ARGF+. Returns +nil+ if called at + * Gets the next 8-bit byte (0..255) from ARGF. Returns +nil+ if called at * the end of the stream. * * For example: @@ -13668,8 +13670,8 @@ argf_getbyte(VALUE argf) * call-seq: * ARGF.readchar -> String or nil * - * Reads the next character from +ARGF+ and returns it as a +String+. Raises - * an +EOFError+ after the last character of the last file has been read. + * Reads the next character from ARGF and returns it as a String. Raises + * an EOFError after the last character of the last file has been read. * * For example: * @@ -13708,8 +13710,8 @@ argf_readchar(VALUE argf) * call-seq: * ARGF.readbyte -> Integer * - * Reads the next 8-bit byte from ARGF and returns it as an +Integer+. Raises - * an +EOFError+ after the last byte of the last file has been read. + * Reads the next 8-bit byte from ARGF and returns it as an Integer. Raises + * an EOFError after the last byte of the last file has been read. * * For example: * @@ -13789,15 +13791,15 @@ argf_block_call_line(ID mid, int argc, VALUE *argv, VALUE argf) * which defaults to your platform's newline character) of each file in * +ARGV+. If a block is supplied, each line in turn will be yielded to the * block, otherwise an enumerator is returned. - * The optional _limit_ argument is an +Integer+ specifying the maximum + * The optional _limit_ argument is an Integer specifying the maximum * length of each line; longer lines will be split according to this limit. * * This method allows you to treat the files supplied on the command line as * a single file consisting of the concatenation of each named file. After * the last line of the first file has been returned, the first line of the - * second file is returned. The +ARGF.filename+ and +ARGF.lineno+ methods can - * be used to determine the filename of the current line and line number of - * the whole input, respectively. + * second file is returned. The ARGF.filename and ARGF.lineno methods can be + * used to determine the filename of the current line and line number of the + * whole input, respectively. * * For example, the following code prints out each line of each named file * prefixed with its line number, displaying the filename once per file: @@ -13831,12 +13833,12 @@ argf_each_line(int argc, VALUE *argv, VALUE argf) * ARGF.each_byte -> an_enumerator * * Iterates over each byte of each file in +ARGV+. - * A byte is returned as an +Integer+ in the range 0..255. + * A byte is returned as an Integer in the range 0..255. * * This method allows you to treat the files supplied on the command line as * a single file consisting of the concatenation of each named file. After * the last byte of the first file has been returned, the first byte of the - * second file is returned. The +ARGF.filename+ method can be used to + * second file is returned. The ARGF.filename method can be used to * determine the filename of the current byte. * * If no block is given, an enumerator is returned instead. @@ -13861,12 +13863,12 @@ argf_each_byte(VALUE argf) * ARGF.each_char {|char| block } -> ARGF * ARGF.each_char -> an_enumerator * - * Iterates over each character of each file in +ARGF+. + * Iterates over each character of each file in ARGF. * * This method allows you to treat the files supplied on the command line as * a single file consisting of the concatenation of each named file. After * the last character of the first file has been returned, the first - * character of the second file is returned. The +ARGF.filename+ method can + * character of the second file is returned. The ARGF.filename method can * be used to determine the name of the file in which the current character * appears. * @@ -13887,12 +13889,12 @@ argf_each_char(VALUE argf) * ARGF.each_codepoint {|codepoint| block } -> ARGF * ARGF.each_codepoint -> an_enumerator * - * Iterates over each codepoint of each file in +ARGF+. + * Iterates over each codepoint of each file in ARGF. * * This method allows you to treat the files supplied on the command line as * a single file consisting of the concatenation of each named file. After * the last codepoint of the first file has been returned, the first - * codepoint of the second file is returned. The +ARGF.filename+ method can + * codepoint of the second file is returned. The ARGF.filename method can * be used to determine the name of the file in which the current codepoint * appears. * @@ -13947,7 +13949,7 @@ argf_filename_getter(ID id, VALUE *var) * call-seq: * ARGF.file -> IO or File object * - * Returns the current file as an +IO+ or +File+ object. + * Returns the current file as an IO or File object. * $stdin is returned when the current file is STDIN. * * For example: @@ -13972,7 +13974,7 @@ argf_file(VALUE argf) * call-seq: * ARGF.binmode -> ARGF * - * Puts +ARGF+ into binary mode. Once a stream is in binary mode, it cannot + * Puts ARGF into binary mode. Once a stream is in binary mode, it cannot * be reset to non-binary mode. This option has the following effects: * * * Newline conversion is disabled. @@ -13993,8 +13995,8 @@ argf_binmode_m(VALUE argf) * call-seq: * ARGF.binmode? -> true or false * - * Returns true if +ARGF+ is being read in binary mode; false otherwise. - * To enable binary mode use +ARGF.binmode+. + * Returns true if ARGF is being read in binary mode; false otherwise. + * To enable binary mode use ARGF.binmode. * * For example: * @@ -14037,7 +14039,7 @@ argf_skip(VALUE argf) * ARGF.close -> ARGF * * Closes the current file and skips to the next file in ARGV. If there are - * no more files to open, just closes the current file. +STDIN+ will not be + * no more files to open, just closes the current file. STDIN will not be * closed. * * For example: @@ -14066,7 +14068,7 @@ argf_close_m(VALUE argf) * ARGF.closed? -> true or false * * Returns _true_ if the current file has been closed; _false_ otherwise. Use - * +ARGF.close+ to actually close the current file. + * ARGF.close to actually close the current file. */ static VALUE argf_closed(VALUE argf) @@ -14092,9 +14094,9 @@ argf_to_s(VALUE argf) * call-seq: * ARGF.inplace_mode -> String * - * Returns the file extension appended to the names of modified files under - * in-place edit mode. This value can be set using +ARGF.inplace_mode=+ or - * passing the +-i+ switch to the Ruby binary. + * Returns the file extension appended to the names of backup copies of + * modified files under in-place edit mode. This value can be set using + * ARGF.inplace_mode= or passing the +-i+ switch to the Ruby binary. */ static VALUE argf_inplace_mode_get(VALUE argf) @@ -14115,8 +14117,8 @@ opt_i_get(ID id, VALUE *var) * ARGF.inplace_mode = ext -> ARGF * * Sets the filename extension for in-place editing mode to the given String. - * Each file being edited has this value appended to its filename. The - * modified file is saved under this new name. + * The backup copy of each file being edited has this value appended to its + * filename. * * For example: * @@ -14127,8 +14129,9 @@ opt_i_get(ID id, VALUE *var) * print line.sub("foo","bar") * end * - * Each line of _file.txt_ has the first occurrence of "foo" replaced with - * "bar", then the new line is written out to _file.txt.bak_. + * First, _file.txt.bak_ is created as a backup copy of _file.txt_. + * Then, each line of _file.txt_ has the first occurrence of "foo" replaced with + * "bar". */ static VALUE argf_inplace_mode_set(VALUE argf, VALUE val) @@ -14306,9 +14309,9 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y) * methods exist in two forms, * * one that returns +nil+ when the end of file is reached, the other - * raises +EOFError+. + * raises EOFError. * - * +EOFError+ is a subclass of +IOError+. + * EOFError is a subclass of IOError. * * file = File.open("/etc/hosts") * file.read @@ -14320,11 +14323,11 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y) /* * Document-class: ARGF * - * +ARGF+ is a stream designed for use in scripts that process files given as + * ARGF is a stream designed for use in scripts that process files given as * command-line arguments or passed in via STDIN. * * The arguments passed to your script are stored in the +ARGV+ Array, one - * argument per element. +ARGF+ assumes that any arguments that aren't + * argument per element. ARGF assumes that any arguments that aren't * filenames have been removed from +ARGV+. For example: * * $ ruby argf.rb --verbose file1 file2 @@ -14333,15 +14336,15 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y) * option = ARGV.shift #=> "--verbose" * ARGV #=> ["file1", "file2"] * - * You can now use +ARGF+ to work with a concatenation of each of these named - * files. For instance, +ARGF.read+ will return the contents of _file1_ + * You can now use ARGF to work with a concatenation of each of these named + * files. For instance, ARGF.read will return the contents of _file1_ * followed by the contents of _file2_. * - * After a file in +ARGV+ has been read +ARGF+ removes it from the Array. + * After a file in +ARGV+ has been read ARGF removes it from the Array. * Thus, after all files have been read +ARGV+ will be empty. * - * You can manipulate +ARGV+ yourself to control what +ARGF+ operates on. If - * you remove a file from +ARGV+, it is ignored by +ARGF+; if you add files to + * You can manipulate +ARGV+ yourself to control what ARGF operates on. If + * you remove a file from +ARGV+, it is ignored by ARGF; if you add files to * +ARGV+, they are treated as if they were named on the command line. For * example: * @@ -14351,7 +14354,7 @@ set_LAST_READ_LINE(VALUE val, ID _x, VALUE *_y) * ARGV.replace ["file2", "file3"] * ARGF.read # Returns the contents of file2 and file3 * - * If +ARGV+ is empty, +ARGF+ acts as if it contained STDIN, i.e. the data + * If +ARGV+ is empty, ARGF acts as if it contained STDIN, i.e. the data * piped to your script. For example: * * $ echo "glark" | ruby -e 'p ARGF.read' diff --git a/io_buffer.c b/io_buffer.c index cf6784e932e410..6ce0dd13dfba76 100644 --- a/io_buffer.c +++ b/io_buffer.c @@ -86,7 +86,8 @@ io_buffer_map_file(struct rb_io_buffer *data, int descriptor, size_t size, off_t if (flags & RB_IO_BUFFER_PRIVATE) { access |= FILE_MAP_COPY; data->flags |= RB_IO_BUFFER_PRIVATE; - } else { + } + else { // This buffer refers to external data. data->flags |= RB_IO_BUFFER_EXTERNAL; } @@ -186,7 +187,8 @@ io_buffer_initialize(struct rb_io_buffer *data, void *base, size_t size, enum rb if (!base) { rb_raise(rb_eIOBufferAllocationError, "Could not allocate buffer!"); } - } else { + } + else { // Otherwise we don't do anything. return; } @@ -304,13 +306,14 @@ io_buffer_for_make_instance(VALUE klass, VALUE string) } struct io_buffer_for_yield_instance_arguments { - VALUE klass; - VALUE string; - VALUE instance; + VALUE klass; + VALUE string; + VALUE instance; }; static VALUE -io_buffer_for_yield_instance(VALUE _arguments) { +io_buffer_for_yield_instance(VALUE _arguments) +{ struct io_buffer_for_yield_instance_arguments *arguments = (struct io_buffer_for_yield_instance_arguments *)_arguments; rb_str_locktmp(arguments->string); @@ -377,17 +380,18 @@ rb_io_buffer_type_for(VALUE klass, VALUE string) // If the string is frozen, both code paths are okay. // If the string is not frozen, if a block is not given, it must be frozen. if (rb_block_given_p()) { - struct io_buffer_for_yield_instance_arguments arguments = { - .klass = klass, - .string = string, - .instance = Qnil, - }; + struct io_buffer_for_yield_instance_arguments arguments = { + .klass = klass, + .string = string, + .instance = Qnil, + }; - return rb_ensure(io_buffer_for_yield_instance, (VALUE)&arguments, io_buffer_for_yield_instance_ensure, (VALUE)&arguments); - } else { - // This internally returns the source string if it's already frozen. - string = rb_str_tmp_frozen_acquire(string); - return io_buffer_for_make_instance(klass, string); + return rb_ensure(io_buffer_for_yield_instance, (VALUE)&arguments, io_buffer_for_yield_instance_ensure, (VALUE)&arguments); + } + else { + // This internally returns the source string if it's already frozen. + string = rb_str_tmp_frozen_acquire(string); + return io_buffer_for_make_instance(klass, string); } } @@ -557,7 +561,8 @@ rb_io_buffer_initialize(int argc, VALUE *argv, VALUE self) if (argc > 0) { size = RB_NUM2SIZE(argv[0]); - } else { + } + else { size = RUBY_IO_BUFFER_DEFAULT_SIZE; } @@ -682,7 +687,8 @@ io_buffer_hexdump(VALUE string, size_t width, char *base, size_t size, int first if (first) { rb_str_catf(string, "0x%08" PRIxSIZE " ", offset); first = 0; - } else { + } + else { rb_str_catf(string, "\n0x%08" PRIxSIZE " ", offset); } @@ -1139,7 +1145,8 @@ rb_io_buffer_slice(VALUE self, VALUE _offset, VALUE _length) return instance; } -int rb_io_buffer_get_bytes(VALUE self, void **base, size_t *size) +int +rb_io_buffer_get_bytes(VALUE self, void **base, size_t *size) { struct rb_io_buffer *data = NULL; TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, data); @@ -1494,28 +1501,28 @@ VALUE rb_io_buffer_get_value(const void* base, size_t size, ID type, size_t offset) { #define READ_TYPE(name) if (type == RB_IO_BUFFER_TYPE_##name) return io_buffer_read_##name(base, size, &offset); - READ_TYPE(U8) - READ_TYPE(S8) - - READ_TYPE(u16) - READ_TYPE(U16) - READ_TYPE(s16) - READ_TYPE(S16) - - READ_TYPE(u32) - READ_TYPE(U32) - READ_TYPE(s32) - READ_TYPE(S32) - - READ_TYPE(u64) - READ_TYPE(U64) - READ_TYPE(s64) - READ_TYPE(S64) - - READ_TYPE(f32) - READ_TYPE(F32) - READ_TYPE(f64) - READ_TYPE(F64) + READ_TYPE(U8); + READ_TYPE(S8); + + READ_TYPE(u16); + READ_TYPE(U16); + READ_TYPE(s16); + READ_TYPE(S16); + + READ_TYPE(u32); + READ_TYPE(U32); + READ_TYPE(s32); + READ_TYPE(S32); + + READ_TYPE(u64); + READ_TYPE(U64); + READ_TYPE(s64); + READ_TYPE(S64); + + READ_TYPE(f32); + READ_TYPE(F32); + READ_TYPE(f64); + READ_TYPE(F64); #undef READ_TYPE rb_raise(rb_eArgError, "Invalid type name!"); @@ -1570,28 +1577,28 @@ void rb_io_buffer_set_value(const void* base, size_t size, ID type, size_t offset, VALUE value) { #define WRITE_TYPE(name) if (type == RB_IO_BUFFER_TYPE_##name) {io_buffer_write_##name(base, size, &offset, value); return;} - WRITE_TYPE(U8) - WRITE_TYPE(S8) - - WRITE_TYPE(u16) - WRITE_TYPE(U16) - WRITE_TYPE(s16) - WRITE_TYPE(S16) - - WRITE_TYPE(u32) - WRITE_TYPE(U32) - WRITE_TYPE(s32) - WRITE_TYPE(S32) - - WRITE_TYPE(u64) - WRITE_TYPE(U64) - WRITE_TYPE(s64) - WRITE_TYPE(S64) - - WRITE_TYPE(f32) - WRITE_TYPE(F32) - WRITE_TYPE(f64) - WRITE_TYPE(F64) + WRITE_TYPE(U8); + WRITE_TYPE(S8); + + WRITE_TYPE(u16); + WRITE_TYPE(U16); + WRITE_TYPE(s16); + WRITE_TYPE(S16); + + WRITE_TYPE(u32); + WRITE_TYPE(U32); + WRITE_TYPE(s32); + WRITE_TYPE(S32); + + WRITE_TYPE(u64); + WRITE_TYPE(U64); + WRITE_TYPE(s64); + WRITE_TYPE(S64); + + WRITE_TYPE(f32); + WRITE_TYPE(F32); + WRITE_TYPE(f64); + WRITE_TYPE(F64); #undef WRITE_TYPE rb_raise(rb_eArgError, "Invalid type name!"); @@ -1665,7 +1672,8 @@ io_buffer_copy_from(struct rb_io_buffer *data, const void *source_base, size_t s // The offset we copy into the buffer: if (argc >= 1) { offset = NUM2SIZET(argv[0]); - } else { + } + else { offset = 0; } @@ -1676,14 +1684,16 @@ io_buffer_copy_from(struct rb_io_buffer *data, const void *source_base, size_t s if (source_offset > source_size) { rb_raise(rb_eArgError, "The given source offset is bigger than the source itself!"); } - } else { + } + else { source_offset = 0; } // The length we are going to copy: if (argc >= 2 && !RB_NIL_P(argv[1])) { length = NUM2SIZET(argv[1]); - } else { + } + else { // Default to the source offset -> source size: length = source_size - source_offset; } @@ -1836,7 +1846,8 @@ io_buffer_get_string(int argc, VALUE *argv, VALUE self) if (argc >= 2 && !RB_NIL_P(argv[1])) { length = NUM2SIZET(argv[1]); - } else { + } + else { length = size - offset; } @@ -1956,7 +1967,8 @@ io_buffer_clear(int argc, VALUE *argv, VALUE self) size_t length; if (argc >= 3) { length = NUM2SIZET(argv[2]); - } else { + } + else { length = data->size - offset; } @@ -1965,8 +1977,9 @@ io_buffer_clear(int argc, VALUE *argv, VALUE self) return self; } -static -size_t io_buffer_default_size(size_t page_size) { +static size_t +io_buffer_default_size(size_t page_size) +{ // Platform agnostic default size, based on empirical performance observation: const size_t platform_agnostic_default_size = 64*1024; @@ -2166,7 +2179,7 @@ static void memory_and(unsigned char * restrict output, unsigned char * restrict base, size_t size, unsigned char * restrict mask, size_t mask_size) { for (size_t offset = 0; offset < size; offset += 1) { - output[offset] = base[offset] & mask[offset % mask_size]; + output[offset] = base[offset] & mask[offset % mask_size]; } } @@ -2206,7 +2219,7 @@ static void memory_or(unsigned char * restrict output, unsigned char * restrict base, size_t size, unsigned char * restrict mask, size_t mask_size) { for (size_t offset = 0; offset < size; offset += 1) { - output[offset] = base[offset] | mask[offset % mask_size]; + output[offset] = base[offset] | mask[offset % mask_size]; } } @@ -2246,7 +2259,7 @@ static void memory_xor(unsigned char * restrict output, unsigned char * restrict base, size_t size, unsigned char * restrict mask, size_t mask_size) { for (size_t offset = 0; offset < size; offset += 1) { - output[offset] = base[offset] ^ mask[offset % mask_size]; + output[offset] = base[offset] ^ mask[offset % mask_size]; } } @@ -2286,7 +2299,7 @@ static void memory_not(unsigned char * restrict output, unsigned char * restrict base, size_t size) { for (size_t offset = 0; offset < size; offset += 1) { - output[offset] = ~base[offset]; + output[offset] = ~base[offset]; } } @@ -2321,7 +2334,7 @@ static inline int io_buffer_overlaps(const struct rb_io_buffer *a, const struct rb_io_buffer *b) { if (a->base > b->base) { - return io_buffer_overlaps(b, a); + return io_buffer_overlaps(b, a); } return (b->base >= a->base) && (b->base <= (void*)((unsigned char *)a->base + a->size)); @@ -2338,7 +2351,7 @@ static void memory_and_inplace(unsigned char * restrict base, size_t size, unsigned char * restrict mask, size_t mask_size) { for (size_t offset = 0; offset < size; offset += 1) { - base[offset] &= mask[offset % mask_size]; + base[offset] &= mask[offset % mask_size]; } } @@ -2384,7 +2397,7 @@ static void memory_or_inplace(unsigned char * restrict base, size_t size, unsigned char * restrict mask, size_t mask_size) { for (size_t offset = 0; offset < size; offset += 1) { - base[offset] |= mask[offset % mask_size]; + base[offset] |= mask[offset % mask_size]; } } @@ -2430,7 +2443,7 @@ static void memory_xor_inplace(unsigned char * restrict base, size_t size, unsigned char * restrict mask, size_t mask_size) { for (size_t offset = 0; offset < size; offset += 1) { - base[offset] ^= mask[offset % mask_size]; + base[offset] ^= mask[offset % mask_size]; } } @@ -2476,7 +2489,7 @@ static void memory_not_inplace(unsigned char * restrict base, size_t size) { for (size_t offset = 0; offset < size; offset += 1) { - base[offset] = ~base[offset]; + base[offset] = ~base[offset]; } } diff --git a/iseq.c b/iseq.c index 34c438e2a295ba..3d40b88a0de1bc 100644 --- a/iseq.c +++ b/iseq.c @@ -773,7 +773,7 @@ prepare_iseq_build(rb_iseq_t *iseq, } ISEQ_COVERAGE_SET(iseq, coverage); if (coverage && ISEQ_BRANCH_COVERAGE(iseq)) - ISEQ_PC2BRANCHINDEX_SET(iseq, rb_ary_tmp_new(0)); + ISEQ_PC2BRANCHINDEX_SET(iseq, rb_ary_hidden_new(0)); return Qtrue; } @@ -2391,7 +2391,7 @@ rb_iseq_disasm_recursive(const rb_iseq_t *iseq, VALUE indent) const struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq); VALUE *code; VALUE str = rb_str_new(0, 0); - VALUE child = rb_ary_tmp_new(3); + VALUE child = rb_ary_hidden_new(3); unsigned int size; unsigned int i; long l; diff --git a/lib/bundler.rb b/lib/bundler.rb index 9fb9ce3e822383..7df22ab3a54813 100644 --- a/lib/bundler.rb +++ b/lib/bundler.rb @@ -53,6 +53,7 @@ module Bundler autoload :GemHelpers, File.expand_path("bundler/gem_helpers", __dir__) autoload :GemVersionPromoter, File.expand_path("bundler/gem_version_promoter", __dir__) autoload :Graph, File.expand_path("bundler/graph", __dir__) + autoload :IncompleteSpecification, File.expand_path("bundler/incomplete_specification", __dir__) autoload :Index, File.expand_path("bundler/index", __dir__) autoload :Injector, File.expand_path("bundler/injector", __dir__) autoload :Installer, File.expand_path("bundler/installer", __dir__) @@ -455,7 +456,7 @@ def unbundled_exec(*args) end def local_platform - return Gem::Platform::RUBY if settings[:force_ruby_platform] + return Gem::Platform::RUBY if settings[:force_ruby_platform] || Gem.platforms == [Gem::Platform::RUBY] Gem::Platform.local end diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb index e1c284130be5d1..0fa646c8ea823c 100644 --- a/lib/bundler/cli.rb +++ b/lib/bundler/cli.rb @@ -218,6 +218,8 @@ def remove(*gems) "Specify the number of jobs to run in parallel" method_option "local", :type => :boolean, :banner => "Do not attempt to fetch gems remotely and use the gem cache instead" + method_option "prefer-local", :type => :boolean, :banner => + "Only attempt to fetch gems remotely if not present locally, even if newer versions are available remotely" method_option "no-cache", :type => :boolean, :banner => "Don't update the existing gem cache." method_option "redownload", :type => :boolean, :aliases => "--force", :banner => @@ -399,9 +401,9 @@ def add(*gems) "Do not attempt to fetch gems remotely and use the gem cache instead" method_option "pre", :type => :boolean, :banner => "Check for newer pre-release gems" method_option "source", :type => :array, :banner => "Check against a specific source" - method_option "filter-strict", :type => :boolean, :banner => + method_option "filter-strict", :type => :boolean, :aliases => "--strict", :banner => "Only list newer versions allowed by your Gemfile requirements" - method_option "strict", :type => :boolean, :aliases => "--update-strict", :banner => + method_option "update-strict", :type => :boolean, :banner => "Strict conservative resolution, do not allow any gem to be updated past latest --patch | --minor | --major" method_option "minor", :type => :boolean, :banner => "Prefer updating only to next minor version" method_option "major", :type => :boolean, :banner => "Prefer updating to next major version (default)" diff --git a/lib/bundler/cli/common.rb b/lib/bundler/cli/common.rb index b547619c6af2c2..0d83a1c07e9386 100644 --- a/lib/bundler/cli/common.rb +++ b/lib/bundler/cli/common.rb @@ -15,6 +15,7 @@ def self.print_post_install_message(name, msg) end def self.output_fund_metadata_summary + return if Bundler.settings["ignore_funding_requests"] definition = Bundler.definition current_dependencies = definition.requested_dependencies current_specs = definition.specs diff --git a/lib/bundler/cli/install.rb b/lib/bundler/cli/install.rb index e9b85f7f6f4b30..851ae9b840f8d6 100644 --- a/lib/bundler/cli/install.rb +++ b/lib/bundler/cli/install.rb @@ -147,8 +147,11 @@ def normalize_groups def normalize_settings Bundler.settings.set_command_option :path, nil if options[:system] Bundler.settings.set_command_option_if_given :path, options[:path] - Bundler.settings.temporary(:path_relative_to_cwd => false) do - Bundler.settings.set_command_option :path, "bundle" if options["standalone"] && Bundler.settings[:path].nil? + + if options["standalone"] && Bundler.settings[:path].nil? && !options["local"] + Bundler.settings.temporary(:path_relative_to_cwd => false) do + Bundler.settings.set_command_option :path, "bundle" + end end bin_option = options["binstubs"] diff --git a/lib/bundler/cli/outdated.rb b/lib/bundler/cli/outdated.rb index d5183b060bbd8e..e9f93fec396d06 100644 --- a/lib/bundler/cli/outdated.rb +++ b/lib/bundler/cli/outdated.rb @@ -46,7 +46,7 @@ def run Bundler::CLI::Common.configure_gem_version_promoter( Bundler.definition, - options + options.merge(:strict => @strict) ) definition_resolution = proc do @@ -129,6 +129,12 @@ def run private + def loaded_from_for(spec) + return unless spec.respond_to?(:loaded_from) + + spec.loaded_from + end + def groups_text(group_text, groups) "#{group_text}#{groups.split(",").size > 1 ? "s" : ""} \"#{groups}\"" end @@ -184,7 +190,10 @@ def print_gems_table(gems_list) def print_gem(current_spec, active_spec, dependency, groups) spec_version = "#{active_spec.version}#{active_spec.git_version}" - spec_version += " (from #{active_spec.loaded_from})" if Bundler.ui.debug? && active_spec.loaded_from + if Bundler.ui.debug? + loaded_from = loaded_from_for(active_spec) + spec_version += " (from #{loaded_from})" if loaded_from + end current_version = "#{current_spec.version}#{current_spec.git_version}" if dependency && dependency.specific? @@ -211,7 +220,7 @@ def gem_column_for(current_spec, active_spec, dependency, groups) dependency = dependency.requirement if dependency ret_val = [active_spec.name, current_version, spec_version, dependency.to_s, groups.to_s] - ret_val << active_spec.loaded_from.to_s if Bundler.ui.debug? + ret_val << loaded_from_for(active_spec).to_s if Bundler.ui.debug? ret_val end diff --git a/lib/bundler/cli/platform.rb b/lib/bundler/cli/platform.rb index 068c765aad4e8c..16d4e0145add4c 100644 --- a/lib/bundler/cli/platform.rb +++ b/lib/bundler/cli/platform.rb @@ -9,7 +9,7 @@ def initialize(options) def run platforms, ruby_version = Bundler.ui.silence do - locked_ruby_version = Bundler.locked_gems && Bundler.locked_gems.ruby_version + locked_ruby_version = Bundler.locked_gems && Bundler.locked_gems.ruby_version.gsub(/p\d+\Z/, "") gemfile_ruby_version = Bundler.definition.ruby_version && Bundler.definition.ruby_version.single_version_string [Bundler.definition.platforms.map {|p| "* #{p}" }, locked_ruby_version || gemfile_ruby_version] diff --git a/lib/bundler/cli/viz.rb b/lib/bundler/cli/viz.rb index 644f9b25cf704b..5c09e009959e49 100644 --- a/lib/bundler/cli/viz.rb +++ b/lib/bundler/cli/viz.rb @@ -23,7 +23,7 @@ def run Bundler.ui.warn "Make sure you have the graphviz ruby gem. You can install it with:" Bundler.ui.warn "`gem install ruby-graphviz`" rescue StandardError => e - raise unless e.message =~ /GraphViz not installed or dot not in PATH/ + raise unless e.message.to_s.include?("GraphViz not installed or dot not in PATH") Bundler.ui.error e.message Bundler.ui.warn "Please install GraphViz. On a Mac with Homebrew, you can run `brew install graphviz`." end diff --git a/lib/bundler/constants.rb b/lib/bundler/constants.rb index 2e4ebb37ee606d..8dd8a5381535c7 100644 --- a/lib/bundler/constants.rb +++ b/lib/bundler/constants.rb @@ -2,6 +2,6 @@ module Bundler WINDOWS = RbConfig::CONFIG["host_os"] =~ /(msdos|mswin|djgpp|mingw)/ - FREEBSD = RbConfig::CONFIG["host_os"] =~ /bsd/ + FREEBSD = RbConfig::CONFIG["host_os"].to_s.include?("bsd") NULL = WINDOWS ? "NUL" : "/dev/null" end diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 8f43befe35c996..34c23796e8fb78 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -70,6 +70,7 @@ def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, opti @unlock = unlock @optional_groups = optional_groups @remote = false + @prefer_local = false @specs = nil @ruby_version = ruby_version @gemfiles = gemfiles @@ -138,13 +139,13 @@ def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, opti @unlock[:gems] ||= @dependencies.map(&:name) else eager_unlock = expand_dependencies(@unlock[:gems] || [], true) - @unlock[:gems] = @locked_specs.for(eager_unlock, false, false).map(&:name) + @unlock[:gems] = @locked_specs.for(eager_unlock, false, platforms).map(&:name) end @dependency_changes = converge_dependencies @local_changes = converge_locals - @locked_specs_incomplete_for_platform = !@locked_specs.for(requested_dependencies & expand_dependencies(locked_dependencies), true, true) + @reresolve = nil @requires = compute_requires end @@ -170,6 +171,13 @@ def resolve_only_locally! resolve end + def resolve_prefering_local! + @prefer_local = true + @remote = true + sources.remote! + resolve + end + def resolve_with_cache! sources.cached! resolve @@ -279,11 +287,8 @@ def resolve end end else - last_resolve = converge_locked_specs - # Run a resolve against the locally available gems Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}") - expanded_dependencies = expand_dependencies(dependencies + metadata_dependencies, true) - Resolver.resolve(expanded_dependencies, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms) + @reresolve = reresolve end end @@ -468,7 +473,7 @@ def most_specific_locked_platform private :sources def nothing_changed? - !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes && !@locked_specs_incomplete_for_platform + !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes end def unlocking? @@ -477,8 +482,14 @@ def unlocking? private + def reresolve + last_resolve = converge_locked_specs + expanded_dependencies = expand_dependencies(dependencies + metadata_dependencies, true) + Resolver.resolve(expanded_dependencies, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms) + end + def filter_specs(specs, deps) - SpecSet.new(specs).for(expand_dependencies(deps, true), false, false) + SpecSet.new(specs).for(expand_dependencies(deps, true), false, platforms) end def materialize(dependencies) @@ -502,11 +513,20 @@ def materialize(dependencies) raise GemNotFound, "Could not find #{missing_specs_list.join(" nor ")}" end - unless specs["bundler"].any? - bundler = sources.metadata_source.specs.search(Gem::Dependency.new("bundler", VERSION)).last - specs["bundler"] = bundler + if @reresolve.nil? + incomplete_specs = specs.incomplete_specs + + if incomplete_specs.any? + Bundler.ui.debug("The lockfile does not have all gems needed for the current platform though, Bundler will still re-resolve dependencies") + @unlock[:gems].concat(incomplete_specs.map(&:name)) + @resolve = reresolve + specs = resolve.materialize(dependencies) + end end + bundler = sources.metadata_source.specs.search(Gem::Dependency.new("bundler", VERSION)).last + specs["bundler"] = bundler + specs end @@ -514,6 +534,19 @@ def precompute_source_requirements_for_indirect_dependencies? @remote && sources.non_global_rubygems_sources.all?(&:dependency_api_available?) && !sources.aggregate_global_source? end + def pin_locally_available_names(source_requirements) + source_requirements.each_with_object({}) do |(name, original_source), new_source_requirements| + local_source = original_source.dup + local_source.local_only! + + new_source_requirements[name] = if local_source.specs.search(name).any? + local_source + else + original_source + end + end + end + def current_ruby_platform_locked? return false unless generic_local_platform == Gem::Platform::RUBY return false if Bundler.settings[:force_ruby_platform] && !@platforms.include?(Gem::Platform::RUBY) @@ -549,7 +582,6 @@ def change_reason [@new_platform, "you added a new platform to your gemfile"], [@path_changes, "the gemspecs for path gems changed"], [@local_changes, "the gemspecs for git local gems changed"], - [@locked_specs_incomplete_for_platform, "the lockfile does not have all gems needed for the current platform"], ].select(&:first).map(&:last).join(", ") end @@ -725,7 +757,7 @@ def converge_specs(specs) # if we won't need the source (according to the lockfile), # don't error if the path/git source isn't available next if specs. - for(requested_dependencies, false, true). + for(requested_dependencies, false). none? {|locked_spec| locked_spec.source == s.source } raise @@ -752,7 +784,7 @@ def converge_specs(specs) def metadata_dependencies @metadata_dependencies ||= [ - Dependency.new("Ruby\0", RubyVersion.system.gem_version), + Dependency.new("Ruby\0", Gem.ruby_version), Dependency.new("RubyGems\0", Gem::VERSION), ] end @@ -779,7 +811,9 @@ def source_requirements # specs will be available later when the resolver knows where to # look for that gemspec (or its dependencies) source_requirements = if precompute_source_requirements_for_indirect_dependencies? - { :default => sources.default_source }.merge(source_map.all_requirements) + all_requirements = source_map.all_requirements + all_requirements = pin_locally_available_names(all_requirements) if @prefer_local + { :default => sources.default_source }.merge(all_requirements) else { :default => Source::RubygemsAggregate.new(sources, source_map) }.merge(source_map.direct_requirements) end @@ -793,7 +827,9 @@ def source_requirements end def requested_groups - groups - Bundler.settings[:without] - @optional_groups + Bundler.settings[:with] + values = groups - Bundler.settings[:without] - @optional_groups + Bundler.settings[:with] + values &= Bundler.settings[:only] unless Bundler.settings[:only].empty? + values end def lockfiles_equal?(current, proposed, preserve_unknown_sections) diff --git a/lib/bundler/dependency.rb b/lib/bundler/dependency.rb index 2449cb64119f48..7f94079e096f26 100644 --- a/lib/bundler/dependency.rb +++ b/lib/bundler/dependency.rb @@ -1,14 +1,11 @@ # frozen_string_literal: true require "rubygems/dependency" -require_relative "force_platform" require_relative "shared_helpers" require_relative "rubygems_ext" module Bundler class Dependency < Gem::Dependency - include ForcePlatform - attr_reader :autorequire attr_reader :groups, :platforms, :gemfile, :git, :github, :branch, :ref, :force_ruby_platform @@ -112,7 +109,7 @@ def initialize(name, version, options = {}, &blk) @env = options["env"] @should_include = options.fetch("should_include", true) @gemfile = options["gemfile"] - @force_ruby_platform = options.fetch("force_ruby_platform", default_force_ruby_platform) + @force_ruby_platform = options["force_ruby_platform"] @autorequire = Array(options["require"] || []) if options.key?("require") end diff --git a/lib/bundler/fetcher/downloader.rb b/lib/bundler/fetcher/downloader.rb index f2aad3a5007a66..0a668eb17c73a2 100644 --- a/lib/bundler/fetcher/downloader.rb +++ b/lib/bundler/fetcher/downloader.rb @@ -68,7 +68,7 @@ def request(uri, headers) raise CertificateFailureError.new(uri) rescue *HTTP_ERRORS => e Bundler.ui.trace e - if e.is_a?(SocketError) || e.message =~ /host down:/ + if e.is_a?(SocketError) || e.message.to_s.include?("host down:") raise NetworkDownError, "Could not reach host #{uri.host}. Check your network " \ "connection and try again." else diff --git a/lib/bundler/force_platform.rb b/lib/bundler/force_platform.rb deleted file mode 100644 index 0648ea9737a07d..00000000000000 --- a/lib/bundler/force_platform.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -module Bundler - module ForcePlatform - private - - # The `:force_ruby_platform` value used by dependencies for resolution, and - # by locked specifications for materialization is `false` by default, except - # for TruffleRuby. TruffleRuby generally needs to force the RUBY platform - # variant unless the name is explicitly allowlisted. - - def default_force_ruby_platform - return false unless Bundler.current_ruby.truffleruby? - - !Gem::Platform::REUSE_AS_BINARY_ON_TRUFFLERUBY.include?(name) - end - end -end diff --git a/lib/bundler/gem_helpers.rb b/lib/bundler/gem_helpers.rb index 6bc4fb4991fb50..0d50d8687b90b5 100644 --- a/lib/bundler/gem_helpers.rb +++ b/lib/bundler/gem_helpers.rb @@ -44,6 +44,12 @@ def platform_specificity_match(spec_platform, user_platform) def select_best_platform_match(specs, platform) matching = specs.select {|spec| spec.match_platform(platform) } + + sort_best_platform_match(matching, platform) + end + module_function :select_best_platform_match + + def sort_best_platform_match(matching, platform) exact = matching.select {|spec| spec.platform == platform } return exact if exact.any? @@ -52,7 +58,7 @@ def select_best_platform_match(specs, platform) sorted_matching.take_while {|spec| same_specificity(platform, spec, exemplary_spec) && same_deps(spec, exemplary_spec) } end - module_function :select_best_platform_match + module_function :sort_best_platform_match class PlatformMatch def self.specificity_score(spec_platform, user_platform) diff --git a/lib/bundler/incomplete_specification.rb b/lib/bundler/incomplete_specification.rb new file mode 100644 index 00000000000000..6d0b9b901c061c --- /dev/null +++ b/lib/bundler/incomplete_specification.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Bundler + class IncompleteSpecification + attr_reader :name, :platform + + def initialize(name, platform) + @name = name + @platform = platform + end + end +end diff --git a/lib/bundler/index.rb b/lib/bundler/index.rb index 5bc24fc0b2060a..00c7a9e00d7c17 100644 --- a/lib/bundler/index.rb +++ b/lib/bundler/index.rb @@ -56,17 +56,17 @@ def search_all(name) # Search this index's specs, and any source indexes that this index knows # about, returning all of the results. - def search(query, base = nil) - sort_specs(unsorted_search(query, base)) + def search(query) + sort_specs(unsorted_search(query)) end - def unsorted_search(query, base) - results = local_search(query, base) + def unsorted_search(query) + results = local_search(query) seen = results.map(&:full_name).uniq unless @sources.empty? @sources.each do |source| - source.unsorted_search(query, base).each do |spec| + source.unsorted_search(query).each do |spec| next if seen.include?(spec.full_name) seen << spec.full_name @@ -89,12 +89,12 @@ def sort_specs(specs) self.class.sort_specs(specs) end - def local_search(query, base = nil) + def local_search(query) case query when Gem::Specification, RemoteSpecification, LazySpecification, EndpointSpecification then search_by_spec(query) when String then specs_by_name(query) - when Gem::Dependency then search_by_dependency(query, base) - when DepProxy then search_by_dependency(query.dep, base) + when Gem::Dependency then search_by_dependency(query) + when DepProxy then search_by_dependency(query.dep) else raise "You can't search for a #{query.inspect}." end @@ -185,11 +185,9 @@ def specs_by_name(name) @specs[name].values end - def search_by_dependency(dependency, base = nil) - @cache[base || false] ||= {} - @cache[base || false][dependency] ||= begin + def search_by_dependency(dependency) + @cache[dependency] ||= begin specs = specs_by_name(dependency.name) - specs += base if base found = specs.select do |spec| next true if spec.source.is_a?(Source::Gemspec) dependency.matches_spec?(spec) diff --git a/lib/bundler/installer.rb b/lib/bundler/installer.rb index f195d3660042f6..b7b0e36dfd85fc 100644 --- a/lib/bundler/installer.rb +++ b/lib/bundler/installer.rb @@ -268,7 +268,14 @@ def resolve_if_needed(options) return false if @definition.nothing_changed? && !@definition.missing_specs? end - options["local"] ? @definition.resolve_with_cache! : @definition.resolve_remotely! + if options["local"] + @definition.resolve_with_cache! + elsif options["prefer-local"] + @definition.resolve_prefering_local! + else + @definition.resolve_remotely! + end + true end diff --git a/lib/bundler/installer/standalone.rb b/lib/bundler/installer/standalone.rb index 248b677233107a..2756626f8a6504 100644 --- a/lib/bundler/installer/standalone.rb +++ b/lib/bundler/installer/standalone.rb @@ -47,7 +47,7 @@ def extensions_dir end def bundler_path - Bundler.root.join(Bundler.settings[:path], "bundler") + Bundler.root.join(Bundler.settings[:path].to_s, "bundler") end def gem_path(path, spec) diff --git a/lib/bundler/lazy_specification.rb b/lib/bundler/lazy_specification.rb index 89b21efc04df15..9f75c7bab263a5 100644 --- a/lib/bundler/lazy_specification.rb +++ b/lib/bundler/lazy_specification.rb @@ -1,16 +1,13 @@ # frozen_string_literal: true -require_relative "force_platform" require_relative "match_platform" module Bundler class LazySpecification - include ForcePlatform include MatchPlatform attr_reader :name, :version, :dependencies, :platform - attr_writer :force_ruby_platform - attr_accessor :source, :remote + attr_accessor :source, :remote, :force_ruby_platform def initialize(name, version, platform, source = nil) @name = name @@ -19,23 +16,16 @@ def initialize(name, version, platform, source = nil) @platform = platform || Gem::Platform::RUBY @source = source @specification = nil - @force_ruby_platform = nil end def full_name - if platform == Gem::Platform::RUBY || platform.nil? + if platform == Gem::Platform::RUBY "#{@name}-#{@version}" else "#{@name}-#{@version}-#{platform}" end end - def force_ruby_platform - return @force_ruby_platform unless @force_ruby_platform.nil? - - default_force_ruby_platform - end - def ==(other) identifier == other.identifier end @@ -71,7 +61,7 @@ def satisfies?(dependency) def to_lock out = String.new - if platform == Gem::Platform::RUBY || platform.nil? + if platform == Gem::Platform::RUBY out << " #{name} (#{version})\n" else out << " #{name} (#{version}-#{platform})\n" @@ -85,27 +75,44 @@ def to_lock out end - def __materialize__ - @specification = if source.is_a?(Source::Gemspec) && source.gemspec.name == name - source.gemspec.tap {|s| s.source = source } - else - search_object = if source.is_a?(Source::Path) - Dependency.new(name, version) - else - ruby_platform_materializes_to_ruby_platform? ? self : Dependency.new(name, version) - end - platform_object = ruby_platform_materializes_to_ruby_platform? ? Gem::Platform.new(platform) : Gem::Platform.local - candidates = source.specs.search(search_object) - same_platform_candidates = candidates.select do |spec| - MatchPlatform.platforms_match?(spec.platform, platform_object) + def materialize_for_installation + source.local! + + candidates = if source.is_a?(Source::Path) || !ruby_platform_materializes_to_ruby_platform? + target_platform = ruby_platform_materializes_to_ruby_platform? ? platform : Bundler.local_platform + + source.specs.search(Dependency.new(name, version)).select do |spec| + MatchPlatform.platforms_match?(spec.platform, target_platform) end - installable_candidates = same_platform_candidates.select do |spec| + else + source.specs.search(self) + end + + return self if candidates.empty? + + __materialize__(candidates) + end + + def materialize_for_resolution + return self unless Gem::Platform.match_spec?(self) + + candidates = source.specs.search(self) + + __materialize__(candidates) + end + + def __materialize__(candidates) + @specification = begin + search = candidates.reverse.find do |spec| spec.is_a?(StubSpecification) || (spec.required_ruby_version.satisfied_by?(Gem.ruby_version) && spec.required_rubygems_version.satisfied_by?(Gem.rubygems_version)) end - search = installable_candidates.last || same_platform_candidates.last - search.dependencies = dependencies if search && (search.is_a?(RemoteSpecification) || search.is_a?(EndpointSpecification)) + if search.nil? && Bundler.frozen_bundle? + search = candidates.last + else + search.dependencies = dependencies if search && search.full_name == full_name && (search.is_a?(RemoteSpecification) || search.is_a?(EndpointSpecification)) + end search end end @@ -115,7 +122,7 @@ def respond_to?(*args) end def to_s - @__to_s ||= if platform == Gem::Platform::RUBY || platform.nil? + @__to_s ||= if platform == Gem::Platform::RUBY "#{name} (#{version})" else "#{name} (#{version}-#{platform})" diff --git a/lib/bundler/man/bundle-add.1 b/lib/bundler/man/bundle-add.1 index 1a7712486198b0..20430a78a02c26 100644 --- a/lib/bundler/man/bundle-add.1 +++ b/lib/bundler/man/bundle-add.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-ADD" "1" "June 2022" "" "" +.TH "BUNDLE\-ADD" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install diff --git a/lib/bundler/man/bundle-binstubs.1 b/lib/bundler/man/bundle-binstubs.1 index d8312c391d9b5c..9c57c7c9c51f0e 100644 --- a/lib/bundler/man/bundle-binstubs.1 +++ b/lib/bundler/man/bundle-binstubs.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-BINSTUBS" "1" "June 2022" "" "" +.TH "BUNDLE\-BINSTUBS" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\-binstubs\fR \- Install the binstubs of the listed gems diff --git a/lib/bundler/man/bundle-cache.1 b/lib/bundler/man/bundle-cache.1 index 935477a3de46b8..fdaaa3b92ac38b 100644 --- a/lib/bundler/man/bundle-cache.1 +++ b/lib/bundler/man/bundle-cache.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CACHE" "1" "June 2022" "" "" +.TH "BUNDLE\-CACHE" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application @@ -9,6 +9,9 @@ .SH "SYNOPSIS" \fBbundle cache\fR . +.P +alias: \fBpackage\fR, \fBpack\fR +. .SH "DESCRIPTION" Copy all of the \fB\.gem\fR files needed to run the application into the \fBvendor/cache\fR directory\. In the future, when running [bundle install(1)][bundle\-install], use the gems in the cache in preference to the ones on \fBrubygems\.org\fR\. . @@ -53,3 +56,6 @@ One way to be sure that you have the right platformed versions of all your gems . .P By default, bundle cache(1) \fIbundle\-cache\.1\.html\fR fetches and also installs the gems to the default location\. To package the dependencies to \fBvendor/cache\fR without installing them to the local install location, you can run \fBbundle cache \-\-no\-install\fR\. +. +.SH "HISTORY" +In Bundler 2\.1, \fBcache\fR took in the functionalities of \fBpackage\fR and now \fBpackage\fR and \fBpack\fR are aliases of \fBcache\fR\. diff --git a/lib/bundler/man/bundle-cache.1.ronn b/lib/bundler/man/bundle-cache.1.ronn index 383adb2ba3bf31..46906d2b485d95 100644 --- a/lib/bundler/man/bundle-cache.1.ronn +++ b/lib/bundler/man/bundle-cache.1.ronn @@ -5,6 +5,8 @@ bundle-cache(1) -- Package your needed `.gem` files into your application `bundle cache` +alias: `package`, `pack` + ## DESCRIPTION Copy all of the `.gem` files needed to run the application into the @@ -70,3 +72,8 @@ By default, [bundle cache(1)](bundle-cache.1.html) fetches and also installs the gems to the default location. To package the dependencies to `vendor/cache` without installing them to the local install location, you can run `bundle cache --no-install`. + +## HISTORY + +In Bundler 2.1, `cache` took in the functionalities of `package` and now +`package` and `pack` are aliases of `cache`. diff --git a/lib/bundler/man/bundle-check.1 b/lib/bundler/man/bundle-check.1 index 0f38d17bd3dce9..5be78862746450 100644 --- a/lib/bundler/man/bundle-check.1 +++ b/lib/bundler/man/bundle-check.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CHECK" "1" "June 2022" "" "" +.TH "BUNDLE\-CHECK" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems diff --git a/lib/bundler/man/bundle-clean.1 b/lib/bundler/man/bundle-clean.1 index e0b2aac549e0e8..2bb95ed2defda4 100644 --- a/lib/bundler/man/bundle-clean.1 +++ b/lib/bundler/man/bundle-clean.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CLEAN" "1" "June 2022" "" "" +.TH "BUNDLE\-CLEAN" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory diff --git a/lib/bundler/man/bundle-config.1 b/lib/bundler/man/bundle-config.1 index 9b60c4c96183d0..9f7887ca91418b 100644 --- a/lib/bundler/man/bundle-config.1 +++ b/lib/bundler/man/bundle-config.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CONFIG" "1" "June 2022" "" "" +.TH "BUNDLE\-CONFIG" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\-config\fR \- Set bundler configuration options @@ -51,7 +51,7 @@ Executing \fBbundle config unset \fR will delete the configuration in both Executing \fBbundle config unset \-\-global \fR will delete the configuration only from the user configuration\. . .P -Executing \fBbundle config unset \-\-local \fR will delete the configuration only from the local application\. +Executing \fBbundle config unset \-\-local \fR will delete the configuration only from the local application\. . .P Executing bundle with the \fBBUNDLE_IGNORE_CONFIG\fR environment variable set will cause it to ignore all configuration\. @@ -74,6 +74,10 @@ Creates a directory (defaults to \fB~/bin\fR) and place any executables from the In deployment mode, Bundler will \'roll\-out\' the bundle for \fBproduction\fR use\. Please check carefully if you want to have this option enabled in \fBdevelopment\fR or \fBtest\fR environments\. . .TP +\fBonly\fR +A space\-separated list of groups to install only gems of the specified groups\. +. +.TP \fBpath\fR The location to install the specified gems to\. This defaults to Rubygems\' setting\. Bundler shares this location with Rubygems, \fBgem install \.\.\.\fR will have gem installed there, too\. Therefore, gems installed without a \fB\-\-path \.\.\.\fR setting will show up by calling \fBgem list\fR\. Accordingly, gems installed to other locations will not get listed\. . @@ -205,6 +209,9 @@ The following is a list of all configuration keys and their purpose\. You can le \fBglobal_gem_cache\fR (\fBBUNDLE_GLOBAL_GEM_CACHE\fR): Whether Bundler should cache all gems globally, rather than locally to the installing Ruby installation\. . .IP "\(bu" 4 +\fBignore_funding_requests\fR (\fBBUNDLE_IGNORE_FUNDING_REQUESTS\fR): When set, no funding requests will be printed\. +. +.IP "\(bu" 4 \fBignore_messages\fR (\fBBUNDLE_IGNORE_MESSAGES\fR): When set, no post install messages will be printed\. To silence a single gem, use dot notation like \fBignore_messages\.httparty true\fR\. . .IP "\(bu" 4 @@ -220,6 +227,9 @@ The following is a list of all configuration keys and their purpose\. You can le \fBno_prune\fR (\fBBUNDLE_NO_PRUNE\fR): Whether Bundler should leave outdated gems unpruned when caching\. . .IP "\(bu" 4 +\fBonly\fR (\fBBUNDLE_ONLY\fR): A space\-separated list of groups to install only gems of the specified groups\. +. +.IP "\(bu" 4 \fBpath\fR (\fBBUNDLE_PATH\fR): The location on disk where all gems in your bundle will be located regardless of \fB$GEM_HOME\fR or \fB$GEM_PATH\fR values\. Bundle gems not found in this location will be installed by \fBbundle install\fR\. Defaults to \fBGem\.dir\fR\. When \-\-deployment is used, defaults to vendor/bundle\. . .IP "\(bu" 4 @@ -288,7 +298,7 @@ The following is a list of all configuration keys and their purpose\. You can le .IP "" 0 . .P -In general, you should set these settings per\-application by using the applicable flag to the bundle install(1) \fIbundle\-install\.1\.html\fR or bundle package(1) \fIbundle\-package\.1\.html\fR command\. +In general, you should set these settings per\-application by using the applicable flag to the bundle install(1) \fIbundle\-install\.1\.html\fR or bundle cache(1) \fIbundle\-cache\.1\.html\fR command\. . .P You can set them globally either via environment variables or \fBbundle config\fR, whichever is preferable for your setup\. If you use both, environment variables will take preference over global settings\. diff --git a/lib/bundler/man/bundle-config.1.ronn b/lib/bundler/man/bundle-config.1.ronn index 31bb3108c8c15f..905c85fcd99867 100644 --- a/lib/bundler/man/bundle-config.1.ronn +++ b/lib/bundler/man/bundle-config.1.ronn @@ -43,8 +43,8 @@ local and global sources. Executing `bundle config unset --global ` will delete the configuration only from the user configuration. -Executing `bundle config unset --local ` will delete the -configuration only from the local application. +Executing `bundle config unset --local ` will delete the configuration +only from the local application. Executing bundle with the `BUNDLE_IGNORE_CONFIG` environment variable set will cause it to ignore all configuration. @@ -74,6 +74,9 @@ The options that can be configured are: `production` use. Please check carefully if you want to have this option enabled in `development` or `test` environments. +* `only`: + A space-separated list of groups to install only gems of the specified groups. + * `path`: The location to install the specified gems to. This defaults to Rubygems' setting. Bundler shares this location with Rubygems, `gem install ...` will @@ -204,6 +207,8 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html). * `global_gem_cache` (`BUNDLE_GLOBAL_GEM_CACHE`): Whether Bundler should cache all gems globally, rather than locally to the installing Ruby installation. +* `ignore_funding_requests` (`BUNDLE_IGNORE_FUNDING_REQUESTS`): + When set, no funding requests will be printed. * `ignore_messages` (`BUNDLE_IGNORE_MESSAGES`): When set, no post install messages will be printed. To silence a single gem, use dot notation like `ignore_messages.httparty true`. @@ -216,6 +221,8 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html). Whether `bundle package` should skip installing gems. * `no_prune` (`BUNDLE_NO_PRUNE`): Whether Bundler should leave outdated gems unpruned when caching. +* `only` (`BUNDLE_ONLY`): + A space-separated list of groups to install only gems of the specified groups. * `path` (`BUNDLE_PATH`): The location on disk where all gems in your bundle will be located regardless of `$GEM_HOME` or `$GEM_PATH` values. Bundle gems not found in this location @@ -273,7 +280,7 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html). A `:`-separated list of groups whose gems bundler should not install. In general, you should set these settings per-application by using the applicable -flag to the [bundle install(1)](bundle-install.1.html) or [bundle package(1)](bundle-package.1.html) command. +flag to the [bundle install(1)](bundle-install.1.html) or [bundle cache(1)](bundle-cache.1.html) command. You can set them globally either via environment variables or `bundle config`, whichever is preferable for your setup. If you use both, environment variables diff --git a/lib/bundler/man/bundle-doctor.1 b/lib/bundler/man/bundle-doctor.1 index 5e76db89c2dcce..6aad9858db4012 100644 --- a/lib/bundler/man/bundle-doctor.1 +++ b/lib/bundler/man/bundle-doctor.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-DOCTOR" "1" "June 2022" "" "" +.TH "BUNDLE\-DOCTOR" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\-doctor\fR \- Checks the bundle for common problems diff --git a/lib/bundler/man/bundle-exec.1 b/lib/bundler/man/bundle-exec.1 index 1702c22e6fd259..210dd178e82143 100644 --- a/lib/bundler/man/bundle-exec.1 +++ b/lib/bundler/man/bundle-exec.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-EXEC" "1" "June 2022" "" "" +.TH "BUNDLE\-EXEC" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\-exec\fR \- Execute a command in the context of the bundle diff --git a/lib/bundler/man/bundle-gem.1 b/lib/bundler/man/bundle-gem.1 index eb66e2d41d787b..0fb6f7d0ab39aa 100644 --- a/lib/bundler/man/bundle-gem.1 +++ b/lib/bundler/man/bundle-gem.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-GEM" "1" "June 2022" "" "" +.TH "BUNDLE\-GEM" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\-gem\fR \- Generate a project skeleton for creating a rubygem diff --git a/lib/bundler/man/bundle-info.1 b/lib/bundler/man/bundle-info.1 index be1a9e1dcd13e3..d3bad843b86b02 100644 --- a/lib/bundler/man/bundle-info.1 +++ b/lib/bundler/man/bundle-info.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INFO" "1" "June 2022" "" "" +.TH "BUNDLE\-INFO" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\-info\fR \- Show information for the given gem in your bundle diff --git a/lib/bundler/man/bundle-init.1 b/lib/bundler/man/bundle-init.1 index 24f1f7543bd4c7..0b3abfeefcec98 100644 --- a/lib/bundler/man/bundle-init.1 +++ b/lib/bundler/man/bundle-init.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INIT" "1" "June 2022" "" "" +.TH "BUNDLE\-INIT" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\-init\fR \- Generates a Gemfile into the current working directory diff --git a/lib/bundler/man/bundle-inject.1 b/lib/bundler/man/bundle-inject.1 index 2dbcd6e37657f8..53f2eaae0a59be 100644 --- a/lib/bundler/man/bundle-inject.1 +++ b/lib/bundler/man/bundle-inject.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INJECT" "1" "June 2022" "" "" +.TH "BUNDLE\-INJECT" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\-inject\fR \- Add named gem(s) with version requirements to Gemfile @@ -30,4 +30,7 @@ bundle inject \'rack\' \'> 0\' .IP "" 0 . .P -This will inject the \'rack\' gem with a version greater than 0 in your [\fBGemfile(5)\fR][Gemfile(5)] and Gemfile\.lock +This will inject the \'rack\' gem with a version greater than 0 in your [\fBGemfile(5)\fR][Gemfile(5)] and Gemfile\.lock\. +. +.P +The \fBbundle inject\fR command was deprecated in Bundler 2\.1 and will be removed in Bundler 3\.0\. diff --git a/lib/bundler/man/bundle-inject.1.ronn b/lib/bundler/man/bundle-inject.1.ronn index f45434189647e3..95704eddadd36c 100644 --- a/lib/bundler/man/bundle-inject.1.ronn +++ b/lib/bundler/man/bundle-inject.1.ronn @@ -19,4 +19,6 @@ Example: bundle inject 'rack' '> 0' This will inject the 'rack' gem with a version greater than 0 in your -[`Gemfile(5)`][Gemfile(5)] and Gemfile.lock +[`Gemfile(5)`][Gemfile(5)] and Gemfile.lock. + +The `bundle inject` command was deprecated in Bundler 2.1 and will be removed in Bundler 3.0. diff --git a/lib/bundler/man/bundle-install.1 b/lib/bundler/man/bundle-install.1 index e8184fd5105998..8e94fe24372266 100644 --- a/lib/bundler/man/bundle-install.1 +++ b/lib/bundler/man/bundle-install.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INSTALL" "1" "June 2022" "" "" +.TH "BUNDLE\-INSTALL" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\-install\fR \- Install the dependencies specified in your Gemfile @@ -70,6 +70,10 @@ The maximum number of parallel download and install jobs\. The default is the nu Do not attempt to connect to \fBrubygems\.org\fR\. Instead, Bundler will use the gems already present in Rubygems\' cache or in \fBvendor/cache\fR\. Note that if an appropriate platform\-specific gem exists on \fBrubygems\.org\fR it will not be found\. . .TP +\fB\-\-prefer\-local\fR +Force using locally installed gems, or gems already present in Rubygems\' cache or in \fBvendor/cache\fR, when resolving, even if newer versions are available remotely\. Only attempt to connect to \fBrubygems\.org\fR for gems that are not present locally\. +. +.TP \fB\-\-no\-cache\fR Do not update the cache in \fBvendor/cache\fR with the newly bundled gems\. This does not remove any gems in the cache but keeps the newly bundled gems from being cached during the install\. . diff --git a/lib/bundler/man/bundle-install.1.ronn b/lib/bundler/man/bundle-install.1.ronn index bec05187f355df..47200ac2d565d1 100644 --- a/lib/bundler/man/bundle-install.1.ronn +++ b/lib/bundler/man/bundle-install.1.ronn @@ -109,6 +109,12 @@ automatically and that requires `bundler` to silently remember them. Since appropriate platform-specific gem exists on `rubygems.org` it will not be found. +* `--prefer-local`: + Force using locally installed gems, or gems already present in Rubygems' cache + or in `vendor/cache`, when resolving, even if newer versions are available + remotely. Only attempt to connect to `rubygems.org` for gems that are not + present locally. + * `--no-cache`: Do not update the cache in `vendor/cache` with the newly bundled gems. This does not remove any gems in the cache but keeps the newly bundled gems from diff --git a/lib/bundler/man/bundle-list.1 b/lib/bundler/man/bundle-list.1 index 5bc3f43943d4e9..3a9cc9a237b9d1 100644 --- a/lib/bundler/man/bundle-list.1 +++ b/lib/bundler/man/bundle-list.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-LIST" "1" "June 2022" "" "" +.TH "BUNDLE\-LIST" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\-list\fR \- List all the gems in the bundle diff --git a/lib/bundler/man/bundle-lock.1 b/lib/bundler/man/bundle-lock.1 index 2934b441719e42..ac03c5478e379b 100644 --- a/lib/bundler/man/bundle-lock.1 +++ b/lib/bundler/man/bundle-lock.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-LOCK" "1" "June 2022" "" "" +.TH "BUNDLE\-LOCK" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\-lock\fR \- Creates / Updates a lockfile without installing diff --git a/lib/bundler/man/bundle-open.1 b/lib/bundler/man/bundle-open.1 index c4e58fb8540f40..be6c5af2488b84 100644 --- a/lib/bundler/man/bundle-open.1 +++ b/lib/bundler/man/bundle-open.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-OPEN" "1" "June 2022" "" "" +.TH "BUNDLE\-OPEN" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\-open\fR \- Opens the source directory for a gem in your bundle diff --git a/lib/bundler/man/bundle-outdated.1 b/lib/bundler/man/bundle-outdated.1 index ee865b3e9702da..fc3d5e8caf0a07 100644 --- a/lib/bundler/man/bundle-outdated.1 +++ b/lib/bundler/man/bundle-outdated.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-OUTDATED" "1" "June 2022" "" "" +.TH "BUNDLE\-OUTDATED" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\-outdated\fR \- List installed gems with newer versions available diff --git a/lib/bundler/man/bundle-platform.1 b/lib/bundler/man/bundle-platform.1 index aab17a429a5c39..f5a90c59e91ef2 100644 --- a/lib/bundler/man/bundle-platform.1 +++ b/lib/bundler/man/bundle-platform.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-PLATFORM" "1" "June 2022" "" "" +.TH "BUNDLE\-PLATFORM" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\-platform\fR \- Displays platform compatibility information @@ -10,7 +10,7 @@ \fBbundle platform\fR [\-\-ruby] . .SH "DESCRIPTION" -\fBplatform\fR will display information from your Gemfile, Gemfile\.lock, and Ruby VM about your platform\. +\fBplatform\fR displays information from your Gemfile, Gemfile\.lock, and Ruby VM about your platform\. . .P For instance, using this Gemfile(5): @@ -21,7 +21,7 @@ For instance, using this Gemfile(5): source "https://rubygems\.org" -ruby "1\.9\.3" +ruby "3\.1\.2" gem "rack" . @@ -30,7 +30,7 @@ gem "rack" .IP "" 0 . .P -If you run \fBbundle platform\fR on Ruby 1\.9\.3, it will display the following output: +If you run \fBbundle platform\fR on Ruby 3\.1\.2, it displays the following output: . .IP "" 4 . @@ -39,10 +39,13 @@ If you run \fBbundle platform\fR on Ruby 1\.9\.3, it will display the following Your platform is: x86_64\-linux Your app has gems that work on these platforms: +* arm64\-darwin\-21 * ruby +* x64\-mingw\-ucrt +* x86_64\-linux Your Gemfile specifies a Ruby version requirement: -* ruby 1\.9\.3 +* ruby 3\.1\.2 Your current platform satisfies the Ruby version requirement\. . @@ -51,11 +54,18 @@ Your current platform satisfies the Ruby version requirement\. .IP "" 0 . .P -\fBplatform\fR will list all the platforms in your \fBGemfile\.lock\fR as well as the \fBruby\fR directive if applicable from your Gemfile(5)\. It will also let you know if the \fBruby\fR directive requirement has been met\. If \fBruby\fR directive doesn\'t match the running Ruby VM, it will tell you what part does not\. +\fBplatform\fR lists all the platforms in your \fBGemfile\.lock\fR as well as the \fBruby\fR directive if applicable from your Gemfile(5)\. It also lets you know if the \fBruby\fR directive requirement has been met\. If \fBruby\fR directive doesn\'t match the running Ruby VM, it tells you what part does not\. . .SH "OPTIONS" . .TP \fB\-\-ruby\fR It will display the ruby directive information, so you don\'t have to parse it from the Gemfile(5)\. +. +.SH "SEE ALSO" +. +.IP "\(bu" 4 +bundle\-lock(1) \fIbundle\-lock\.1\.ronn\fR +. +.IP "" 0 diff --git a/lib/bundler/man/bundle-platform.1.ronn b/lib/bundler/man/bundle-platform.1.ronn index b5d3283fb6e3cb..eb9baa1c62fca9 100644 --- a/lib/bundler/man/bundle-platform.1.ronn +++ b/lib/bundler/man/bundle-platform.1.ronn @@ -7,36 +7,43 @@ bundle-platform(1) -- Displays platform compatibility information ## DESCRIPTION -`platform` will display information from your Gemfile, Gemfile.lock, and Ruby +`platform` displays information from your Gemfile, Gemfile.lock, and Ruby VM about your platform. For instance, using this Gemfile(5): source "https://rubygems.org" - ruby "1.9.3" + ruby "3.1.2" gem "rack" -If you run `bundle platform` on Ruby 1.9.3, it will display the following output: +If you run `bundle platform` on Ruby 3.1.2, it displays the following output: Your platform is: x86_64-linux Your app has gems that work on these platforms: + * arm64-darwin-21 * ruby + * x64-mingw-ucrt + * x86_64-linux Your Gemfile specifies a Ruby version requirement: - * ruby 1.9.3 + * ruby 3.1.2 Your current platform satisfies the Ruby version requirement. -`platform` will list all the platforms in your `Gemfile.lock` as well as the -`ruby` directive if applicable from your Gemfile(5). It will also let you know +`platform` lists all the platforms in your `Gemfile.lock` as well as the +`ruby` directive if applicable from your Gemfile(5). It also lets you know if the `ruby` directive requirement has been met. If `ruby` directive doesn't -match the running Ruby VM, it will tell you what part does not. +match the running Ruby VM, it tells you what part does not. ## OPTIONS * `--ruby`: It will display the ruby directive information, so you don't have to parse it from the Gemfile(5). + +## SEE ALSO + +* [bundle-lock(1)](bundle-lock.1.ronn) diff --git a/lib/bundler/man/bundle-pristine.1 b/lib/bundler/man/bundle-pristine.1 index a0a5ac1a9bb4c6..44e5a83a01bb52 100644 --- a/lib/bundler/man/bundle-pristine.1 +++ b/lib/bundler/man/bundle-pristine.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-PRISTINE" "1" "June 2022" "" "" +.TH "BUNDLE\-PRISTINE" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\-pristine\fR \- Restores installed gems to their pristine condition diff --git a/lib/bundler/man/bundle-remove.1 b/lib/bundler/man/bundle-remove.1 index f6055716c78d35..29ec2460181e2b 100644 --- a/lib/bundler/man/bundle-remove.1 +++ b/lib/bundler/man/bundle-remove.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-REMOVE" "1" "June 2022" "" "" +.TH "BUNDLE\-REMOVE" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\-remove\fR \- Removes gems from the Gemfile diff --git a/lib/bundler/man/bundle-show.1 b/lib/bundler/man/bundle-show.1 index 14db8075f6df29..227b1c8a1e361c 100644 --- a/lib/bundler/man/bundle-show.1 +++ b/lib/bundler/man/bundle-show.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-SHOW" "1" "June 2022" "" "" +.TH "BUNDLE\-SHOW" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\-show\fR \- Shows all the gems in your bundle, or the path to a gem diff --git a/lib/bundler/man/bundle-update.1 b/lib/bundler/man/bundle-update.1 index b7e2b788124a4a..7d0988bfa55d20 100644 --- a/lib/bundler/man/bundle-update.1 +++ b/lib/bundler/man/bundle-update.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-UPDATE" "1" "June 2022" "" "" +.TH "BUNDLE\-UPDATE" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\-update\fR \- Update your gems to the latest available versions diff --git a/lib/bundler/man/bundle-viz.1 b/lib/bundler/man/bundle-viz.1 index f93ea158358de3..f6f51cde0eca59 100644 --- a/lib/bundler/man/bundle-viz.1 +++ b/lib/bundler/man/bundle-viz.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-VIZ" "1" "June 2022" "" "" +.TH "BUNDLE\-VIZ" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\-viz\fR \- Generates a visual dependency graph for your Gemfile diff --git a/lib/bundler/man/bundle.1 b/lib/bundler/man/bundle.1 index e6e6cdce7b2570..f683e78cc6e25e 100644 --- a/lib/bundler/man/bundle.1 +++ b/lib/bundler/man/bundle.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE" "1" "June 2022" "" "" +.TH "BUNDLE" "1" "July 2022" "" "" . .SH "NAME" \fBbundle\fR \- Ruby Dependency Management @@ -43,8 +43,8 @@ Install the gems specified by the \fBGemfile\fR or \fBGemfile\.lock\fR Update dependencies to their latest versions . .TP -\fBbundle package(1)\fR \fIbundle\-package\.1\.html\fR -Package the \.gem files required by your application into the \fBvendor/cache\fR directory +\fBbundle cache(1)\fR \fIbundle\-cache\.1\.html\fR +Package the \.gem files required by your application into the \fBvendor/cache\fR directory (aliases: \fBbundle package\fR, \fBbundle pack\fR) . .TP \fBbundle exec(1)\fR \fIbundle\-exec\.1\.html\fR @@ -81,7 +81,7 @@ Show the source location of a particular gem in the bundle Show all of the outdated gems in the current bundle . .TP -\fBbundle console(1)\fR +\fBbundle console(1)\fR (deprecated) Start an IRB session in the current bundle . .TP @@ -127,7 +127,7 @@ When running a command that isn\'t listed in PRIMARY COMMANDS or UTILITIES, Bund These commands are obsolete and should no longer be used: . .IP "\(bu" 4 -\fBbundle cache(1)\fR +\fBbundle inject(1)\fR . .IP "" 0 diff --git a/lib/bundler/man/bundle.1.ronn b/lib/bundler/man/bundle.1.ronn index 86d771f024c60f..8f0159eee549c5 100644 --- a/lib/bundler/man/bundle.1.ronn +++ b/lib/bundler/man/bundle.1.ronn @@ -36,9 +36,9 @@ We divide `bundle` subcommands into primary commands and utilities: * [`bundle update(1)`](bundle-update.1.html): Update dependencies to their latest versions -* [`bundle package(1)`](bundle-package.1.html): +* [`bundle cache(1)`](bundle-cache.1.html): Package the .gem files required by your application into the - `vendor/cache` directory + `vendor/cache` directory (aliases: `bundle package`, `bundle pack`) * [`bundle exec(1)`](bundle-exec.1.html): Execute a script in the current bundle @@ -67,7 +67,7 @@ We divide `bundle` subcommands into primary commands and utilities: * [`bundle outdated(1)`](bundle-outdated.1.html): Show all of the outdated gems in the current bundle -* `bundle console(1)`: +* `bundle console(1)` (deprecated): Start an IRB session in the current bundle * [`bundle open(1)`](bundle-open.1.html): @@ -107,4 +107,4 @@ and execute it, passing down any extra arguments to it. These commands are obsolete and should no longer be used: -* `bundle cache(1)` +* `bundle inject(1)` diff --git a/lib/bundler/man/gemfile.5 b/lib/bundler/man/gemfile.5 index 6ea1602ea41f09..63a16ca3ff48bb 100644 --- a/lib/bundler/man/gemfile.5 +++ b/lib/bundler/man/gemfile.5 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "GEMFILE" "5" "June 2022" "" "" +.TH "GEMFILE" "5" "July 2022" "" "" . .SH "NAME" \fBGemfile\fR \- A format for describing gem dependencies for Ruby programs diff --git a/lib/bundler/remote_specification.rb b/lib/bundler/remote_specification.rb index 4e966b820aa565..b5d7e3a6c9a61b 100644 --- a/lib/bundler/remote_specification.rb +++ b/lib/bundler/remote_specification.rb @@ -16,7 +16,8 @@ class RemoteSpecification def initialize(name, version, platform, spec_fetcher) @name = name @version = Gem::Version.create version - @platform = platform + @original_platform = platform || Gem::Platform::RUBY + @platform = Gem::Platform.new(platform) @spec_fetcher = spec_fetcher @dependencies = nil end @@ -35,10 +36,10 @@ def required_rubygems_version end def full_name - if platform == Gem::Platform::RUBY || platform.nil? + if @original_platform == Gem::Platform::RUBY "#{@name}-#{@version}" else - "#{@name}-#{@version}-#{platform}" + "#{@name}-#{@version}-#{@original_platform}" end end @@ -105,7 +106,7 @@ def to_ary end def _remote_specification - @_remote_specification ||= @spec_fetcher.fetch_spec([@name, @version, @platform]) + @_remote_specification ||= @spec_fetcher.fetch_spec([@name, @version, @original_platform]) @_remote_specification || raise(GemspecError, "Gemspec data for #{full_name} was" \ " missing from the server! Try installing with `--full-index` as a workaround.") end diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index 972a4c254dc1f0..40bc247b32253d 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -22,17 +22,16 @@ def self.resolve(requirements, source_requirements = {}, base = [], gem_version_ metadata_requirements, regular_requirements = requirements.partition {|dep| dep.name.end_with?("\0") } resolver = new(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms, metadata_requirements) result = resolver.start(requirements) - SpecSet.new(SpecSet.new(result).for(regular_requirements)) + SpecSet.new(SpecSet.new(result).for(regular_requirements, false, platforms)) end def initialize(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms, metadata_requirements) @source_requirements = source_requirements @metadata_requirements = metadata_requirements - @base = base @resolver = Molinillo::Resolver.new(self, self) @search_for = {} @base_dg = Molinillo::DependencyGraph.new - @base.each do |ls| + @base = base.materialized_for_resolution do |ls| dep = Dependency.new(ls.name, ls.version) @base_dg.add_vertex(ls.name, DepProxy.get_proxy(dep, ls.platform), true) end @@ -111,7 +110,7 @@ def search_for(dependency_proxy) dependency = dependency_proxy.dep name = dependency.name @search_for[dependency_proxy] ||= begin - results = results_for(dependency, @base[name]) + results = results_for(dependency) + @base[name].select {|spec| requirement_satisfied_by?(dependency, nil, spec) } if vertex = @base_dg.vertex_named(name) locked_requirement = vertex.payload.requirement @@ -176,8 +175,8 @@ def source_for(name) @source_requirements[name] || @source_requirements[:default] end - def results_for(dependency, base) - index_for(dependency).search(dependency, base) + def results_for(dependency) + index_for(dependency).search(dependency) end def name_for(dependency) diff --git a/lib/bundler/ruby_version.rb b/lib/bundler/ruby_version.rb index 3f51cf4528a656..9161c6afde4ef6 100644 --- a/lib/bundler/ruby_version.rb +++ b/lib/bundler/ruby_version.rb @@ -32,12 +32,12 @@ def initialize(versions, patchlevel, engine, engine_version) @engine = engine && engine.to_s || "ruby" @engine_versions = (engine_version && Array(engine_version)) || @versions @engine_gem_version = Gem::Requirement.create(@engine_versions.first).requirements.first.last - @patchlevel = patchlevel + @patchlevel = patchlevel || (@gem_version.prerelease? ? "-1" : nil) end def to_s(versions = self.versions) output = String.new("ruby #{versions_string(versions)}") - output << "p#{patchlevel}" if patchlevel + output << "p#{patchlevel}" if patchlevel && patchlevel != "-1" output << " (#{engine} #{versions_string(engine_versions)})" unless engine == "ruby" output @@ -46,7 +46,7 @@ def to_s(versions = self.versions) # @private PATTERN = / ruby\s - ([\d.]+) # ruby version + (\d+\.\d+\.\d+(?:\.\S+)?) # ruby version (?:p(-?\d+))? # optional patchlevel (?:\s\((\S+)\s(.+)\))? # optional engine info /xo.freeze @@ -103,8 +103,8 @@ def versions_string(versions) def self.system ruby_engine = RUBY_ENGINE.dup - ruby_version = RUBY_VERSION.dup - ruby_engine_version = RUBY_ENGINE_VERSION.dup + ruby_version = Gem.ruby_version.to_s + ruby_engine_version = RUBY_ENGINE == "ruby" ? ruby_version : RUBY_ENGINE_VERSION.dup patchlevel = RUBY_PATCHLEVEL.to_s @ruby_version ||= RubyVersion.new(ruby_version, patchlevel, ruby_engine, ruby_engine_version) diff --git a/lib/bundler/rubygems_ext.rb b/lib/bundler/rubygems_ext.rb index d679d20c21efa2..938c58e64d855d 100644 --- a/lib/bundler/rubygems_ext.rb +++ b/lib/bundler/rubygems_ext.rb @@ -17,6 +17,15 @@ require_relative "match_platform" +# Cherry-pick fixes to `Gem.ruby_version` to be useful for modern Bundler +# versions and ignore patchlevels +# (https://github.com/rubygems/rubygems/pull/5472, +# https://github.com/rubygems/rubygems/pull/5486). May be removed once RubyGems +# 3.3.12 support is dropped. +unless Gem.ruby_version.to_s == RUBY_VERSION || RUBY_PATCHLEVEL == -1 + Gem.instance_variable_set(:@ruby_version, Gem::Version.new(RUBY_VERSION)) +end + module Gem class Specification include ::Bundler::MatchPlatform @@ -146,6 +155,10 @@ class Dependency alias_method :eql?, :== + def force_ruby_platform + false + end + def encode_with(coder) to_yaml_properties.each do |ivar| coder[ivar.to_s.sub(/^@/, "")] = instance_variable_get(ivar) @@ -222,9 +235,27 @@ class Platform MINGW = Gem::Platform.new("x86-mingw32") X64_MINGW = [Gem::Platform.new("x64-mingw32"), Gem::Platform.new("x64-mingw-ucrt")].freeze + end + + Platform.singleton_class.module_eval do + unless Platform.singleton_methods.include?(:match_spec?) + def match_spec?(spec) + match_gem?(spec.platform, spec.name) + end + + def match_gem?(platform, gem_name) + match_platforms?(platform, Gem.platforms) + end - if RUBY_ENGINE == "truffleruby" && !defined?(REUSE_AS_BINARY_ON_TRUFFLERUBY) - REUSE_AS_BINARY_ON_TRUFFLERUBY = %w[libv8 sorbet-static].freeze + private + + def match_platforms?(platform, platforms) + platforms.any? do |local_platform| + platform.nil? || + local_platform == platform || + (local_platform != Gem::Platform::RUBY && local_platform =~ platform) + end + end end end diff --git a/lib/bundler/rubygems_gem_installer.rb b/lib/bundler/rubygems_gem_installer.rb index 12cc809664cfad..13c2d258824b55 100644 --- a/lib/bundler/rubygems_gem_installer.rb +++ b/lib/bundler/rubygems_gem_installer.rb @@ -72,10 +72,11 @@ def build_extensions return super end - extension_dir = Pathname.new(extension_dir) build_complete = SharedHelpers.filesystem_access(extension_cache_path.join("gem.build_complete"), :read, &:file?) if build_complete && !options[:force] - SharedHelpers.filesystem_access(extension_dir.parent, &:mkpath) + SharedHelpers.filesystem_access(File.dirname(extension_dir)) do |p| + FileUtils.mkpath p + end SharedHelpers.filesystem_access(extension_cache_path) do FileUtils.cp_r extension_cache_path, extension_dir end diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb index 398c66055ac179..cf5675274e6087 100644 --- a/lib/bundler/settings.rb +++ b/lib/bundler/settings.rb @@ -57,6 +57,7 @@ class Settings ].freeze ARRAY_KEYS = %w[ + only with without ].freeze diff --git a/lib/bundler/source/metadata.rb b/lib/bundler/source/metadata.rb index 185fe7082474a8..23531b8bd4bf0e 100644 --- a/lib/bundler/source/metadata.rb +++ b/lib/bundler/source/metadata.rb @@ -5,7 +5,7 @@ class Source class Metadata < Source def specs @specs ||= Index.build do |idx| - idx << Gem::Specification.new("Ruby\0", RubyVersion.system.gem_version) + idx << Gem::Specification.new("Ruby\0", Gem.ruby_version) idx << Gem::Specification.new("RubyGems\0", Gem::VERSION) do |s| s.required_rubygems_version = Gem::Requirement.default end diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb index 06257ac93fd324..735cdac126c916 100644 --- a/lib/bundler/spec_set.rb +++ b/lib/bundler/spec_set.rb @@ -11,40 +11,33 @@ def initialize(specs) @specs = specs end - def for(dependencies, check = false, match_current_platform = false) - # dep.name => [list, of, deps] - handled = Hash.new {|h, k| h[k] = [] } - deps = dependencies.dup + def for(dependencies, check = false, platforms = [nil]) + handled = ["bundler"].product(platforms).map {|k| [k, true] }.to_h + deps = dependencies.product(platforms) specs = [] loop do break unless dep = deps.shift - next if handled[dep.name].any? {|d| match_current_platform || d.__platform == dep.__platform } || dep.name == "bundler" - # use a hash here to ensure constant lookup time in the `any?` call above - handled[dep.name] << dep + key = [dep[0].name, dep[1]] + next if handled.key?(key) - specs_for_dep = specs_for_dependency(dep, match_current_platform) + handled[key] = true + + specs_for_dep = specs_for_dependency(*dep) if specs_for_dep.any? specs.concat(specs_for_dep) specs_for_dep.first.dependencies.each do |d| next if d.type == :development - d = DepProxy.get_proxy(Dependency.new(d.name, d.requirement), dep.__platform) unless match_current_platform - deps << d + deps << [d, dep[1]] end elsif check - return false + specs << IncompleteSpecification.new(*key) end end - if spec = lookup["bundler"].first - specs << spec - end - - specs.uniq! unless match_current_platform - - check ? true : specs + specs end def [](key) @@ -71,13 +64,8 @@ def to_hash end def materialize(deps) - materialized = self.for(deps, false, true) + materialized = self.for(deps, true) - materialized.map! do |s| - next s unless s.is_a?(LazySpecification) - s.source.local! - s.__materialize__ || s - end SpecSet.new(materialized) end @@ -87,18 +75,30 @@ def materialize(deps) def materialized_for_all_platforms @specs.map do |s| next s unless s.is_a?(LazySpecification) - s.source.local! s.source.remote! - spec = s.__materialize__ + spec = s.materialize_for_installation raise GemNotFound, "Could not find #{s.full_name} in any of the sources" unless spec spec end end + def materialized_for_resolution + materialized = @specs.map do |s| + spec = s.materialize_for_resolution + yield spec if spec + spec + end.compact + SpecSet.new(materialized) + end + def missing_specs @specs.select {|s| s.is_a?(LazySpecification) } end + def incomplete_specs + @specs.select {|s| s.is_a?(IncompleteSpecification) } + end + def merge(set) arr = sorted.dup set.each do |set_spec| @@ -173,13 +173,13 @@ def tsort_each_node @specs.sort_by(&:name).each {|s| yield s } end - def specs_for_dependency(dep, match_current_platform) + def specs_for_dependency(dep, platform) specs_for_name = lookup[dep.name] - if match_current_platform - GemHelpers.select_best_platform_match(specs_for_name, Bundler.local_platform) + if platform.nil? + matching_specs = specs_for_name.map {|s| s.materialize_for_installation if Gem::Platform.match_spec?(s) }.compact + GemHelpers.sort_best_platform_match(matching_specs, Bundler.local_platform) else - specs_for_name_and_platform = GemHelpers.select_best_platform_match(specs_for_name, dep.force_ruby_platform ? Gem::Platform::RUBY : dep.__platform) - specs_for_name_and_platform.any? ? specs_for_name_and_platform : specs_for_name + GemHelpers.select_best_platform_match(specs_for_name, dep.force_ruby_platform ? Gem::Platform::RUBY : platform) end end diff --git a/lib/bundler/templates/Executable b/lib/bundler/templates/Executable index f6487e3c89d0c9..9ff6f00898815b 100644 --- a/lib/bundler/templates/Executable +++ b/lib/bundler/templates/Executable @@ -13,7 +13,7 @@ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("<%= relative_gemfile_path %>", __dir bundle_binstub = File.expand_path("bundle", __dir__) if File.file?(bundle_binstub) - if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") load(bundle_binstub) else abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. diff --git a/lib/bundler/templates/Executable.bundler b/lib/bundler/templates/Executable.bundler index 51650c7664a21e..77f90e735c3adf 100644 --- a/lib/bundler/templates/Executable.bundler +++ b/lib/bundler/templates/Executable.bundler @@ -62,8 +62,9 @@ m = Module.new do def bundler_requirement @bundler_requirement ||= - env_var_version || cli_arg_version || - bundler_requirement_for(lockfile_version) + env_var_version || + cli_arg_version || + bundler_requirement_for(lockfile_version) end def bundler_requirement_for(version) diff --git a/lib/bundler/templates/Executable.standalone b/lib/bundler/templates/Executable.standalone index d591e3fc045948..3117a27e86ff2d 100644 --- a/lib/bundler/templates/Executable.standalone +++ b/lib/bundler/templates/Executable.standalone @@ -1,4 +1,6 @@ #!/usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %> +# frozen_string_literal: true + # # This file was generated by Bundler. # diff --git a/lib/fileutils.rb b/lib/fileutils.rb index 003b4bdd827f5a..7eb66dda0c83a3 100644 --- a/lib/fileutils.rb +++ b/lib/fileutils.rb @@ -440,6 +440,8 @@ def fu_mkdir(path, mode) #:nodoc: # Raises an exception if a directory does not exist # or if for any reason a directory cannot be removed. # + # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting]. + # def rmdir(list, parents: nil, noop: nil, verbose: nil) list = fu_list(list) fu_output_message "rmdir #{parents ? '-p ' : ''}#{list.join ' '}" if verbose @@ -1261,6 +1263,8 @@ def rm_f(list, noop: nil, verbose: nil) # rm -r src0.dat src0.txt # rm -r src1 # + # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting]. + # def rm_r(list, force: nil, noop: nil, verbose: nil, secure: nil) list = fu_list(list) fu_output_message "rm -r#{force ? 'f' : ''} #{list.join ' '}" if verbose @@ -1290,6 +1294,8 @@ def rm_r(list, force: nil, noop: nil, verbose: nil, secure: nil) # # FileUtils.rmtree is an alias for FileUtils.rm_rf. # + # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting]. + # def rm_rf(list, noop: nil, verbose: nil, secure: nil) rm_r list, force: true, noop: noop, verbose: verbose, secure: secure end @@ -1311,6 +1317,8 @@ def rm_rf(list, noop: nil, verbose: nil, secure: nil) # Optional argument +force+ specifies whether to ignore # raised exceptions of StandardError and its descendants. # + # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting]. + # def remove_entry_secure(path, force = false) unless fu_have_symlink? remove_entry path, force @@ -1431,6 +1439,8 @@ def remove_entry(path, force = false) # Optional argument +force+ specifies whether to ignore # raised exceptions of StandardError and its descendants. # + # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting]. + # def remove_file(path, force = false) Entry_.new(path).remove_file rescue @@ -1448,6 +1458,8 @@ def remove_file(path, force = false) # Optional argument +force+ specifies whether to ignore # raised exceptions of StandardError and its descendants. # + # Related: {methods for deleting}[rdoc-ref:FileUtils@Deleting]. + # def remove_dir(path, force = false) remove_entry path, force # FIXME?? check if it is a directory end @@ -1546,7 +1558,7 @@ def compare_stream(a, b) # using {File.chown}[https://docs.ruby-lang.org/en/master/File.html#method-c-chown]. # - mode: permissions - changes the permissions. # using {File.chmod}[https://docs.ruby-lang.org/en/master/File.html#method-c-chmod]. - # - noop: true - does not remove entries; returns +nil+. + # - noop: true - does not copy entries; returns +nil+. # - owner: owner - changes the owner if not +nil+, # using {File.chown}[https://docs.ruby-lang.org/en/master/File.html#method-c-chown]. # - preserve: true - preserve timestamps diff --git a/lib/irb/color_printer.rb b/lib/irb/color_printer.rb index 78f0b51520324f..1127bcecb4932c 100644 --- a/lib/irb/color_printer.rb +++ b/lib/irb/color_printer.rb @@ -37,6 +37,9 @@ def text(str, width = nil) width ||= str.length case str + when '' + when ',', '=>', '[', ']', '{', '}', '..', '...', /\A@\w+\z/ + super(str, width) when /\A#' super(Color.colorize(str, [:GREEN]), width) else diff --git a/lib/mkmf.rb b/lib/mkmf.rb index a6ec9bae5d3ebc..efe3419fd700fb 100644 --- a/lib/mkmf.rb +++ b/lib/mkmf.rb @@ -2076,6 +2076,11 @@ def configuration(srcdir) ruby_version = #{RbConfig::CONFIG['ruby_version']} ruby = #{$ruby.sub(%r[\A#{Regexp.quote(RbConfig::CONFIG['bindir'])}(?=/|\z)]) {'$(bindir)'}} RUBY = $(ruby#{sep}) +BUILTRUBY = #{if defined?($builtruby) && $builtruby + $builtruby + else + File.join('$(bindir)', CONFIG["RUBY_INSTALL_NAME"] + CONFIG['EXEEXT']) + end} ruby_headers = #{headers.join(' ')} RM = #{config_string('RM', &possible_command) || '$(RUBY) -run -e rm -- -f'} diff --git a/lib/optparse.rb b/lib/optparse.rb index ec37bde3bdd446..1d42c79045664d 100644 --- a/lib/optparse.rb +++ b/lib/optparse.rb @@ -765,15 +765,15 @@ def pretty_head # :nodoc: end # - # Switch that takes an argument, which does not begin with '-'. + # Switch that takes an argument, which does not begin with '-' or is '-'. # class PlacedArgument < self # - # Returns nil if argument is not present or begins with '-'. + # Returns nil if argument is not present or begins with '-' and is not '-'. # def parse(arg, argv, &error) - if !(val = arg) and (argv.empty? or /\A-/ =~ (val = argv[0])) + if !(val = arg) and (argv.empty? or /\A-./ =~ (val = argv[0])) return nil, block, nil end opt = (val = parse_arg(val, &error))[1] diff --git a/lib/racc/parser-text.rb b/lib/racc/parser-text.rb index 4188fa853dba47..0579f4ce9b13fd 100644 --- a/lib/racc/parser-text.rb +++ b/lib/racc/parser-text.rb @@ -22,7 +22,7 @@ module Racc class ParseError < StandardError; end end unless defined?(::ParseError) - ParseError = Racc::ParseError + ParseError = Racc::ParseError # :nodoc: end # Racc is a LALR(1) parser generator. diff --git a/lib/rdoc/markup.rb b/lib/rdoc/markup.rb index f7aa02fd9f7813..7fec1c686970cf 100644 --- a/lib/rdoc/markup.rb +++ b/lib/rdoc/markup.rb @@ -97,289 +97,7 @@ # # = \RDoc Markup Reference # -# == Block Markup -# -# === Paragraphs and Verbatim -# -# The markup engine looks for a document's natural left margin. This is -# used as the initial margin for the document. -# -# Consecutive lines starting at this margin are considered to be a -# paragraph. Empty lines separate paragraphs. -# -# Any line that starts to the right of the current margin is treated -# as verbatim text. This is useful for code listings: -# -# 3.times { puts "Ruby" } -# -# In verbatim text, two or more blank lines are collapsed into one, -# and trailing blank lines are removed: -# -# This is the first line -# -# -# This is the second non-blank line, -# after 2 blank lines in the source markup. -# -# -# There were two trailing blank lines right above this paragraph, that -# have been removed. In addition, the verbatim text has been shifted -# left, so the amount of indentation of verbatim text is unimportant. -# -# For HTML output RDoc makes a small effort to determine if a verbatim section -# contains Ruby source code. If so, the verbatim block will be marked up as -# HTML. Triggers include "def", "class", "module", "require", the "hash -# rocket"# (=>) or a block call with a parameter. -# -# === Headers -# -# A line starting with an equal sign (=) is treated as a -# heading. Level one headings have one equals sign, level two headings -# have two, and so on until level six, which is the maximum -# (seven hyphens or more result in a level six heading). -# -# For example, the above header was obtained with: -# -# === Headers -# -# In HTML output headers have an id matching their name. The above example's -# HTML is: -# -#

Headers

-# -# If a heading is inside a method body the id will be prefixed with the -# method's id. If the above header where in the documentation for a method -# such as: -# -# ## -# # This method does fun things -# # -# # = Example -# # -# # Example of fun things goes here ... -# -# def do_fun_things -# end -# -# The header's id would be: -# -#

Example

-# -# The label can be linked-to using SomeClass@Headers. See -# {Links}[rdoc-ref:RDoc::Markup@Links] for further details. -# -# === Rules -# -# A line starting with three or more hyphens (at the current indent) -# generates a horizontal rule. -# -# --- -# -# produces: -# -# --- -# -# === Simple Lists -# -# If a paragraph starts with a "*", "-", "." or ".", -# then it is taken to be the start of a list. The margin is increased to be -# the first non-space following the list start flag. Subsequent lines -# should be indented to this new margin until the list ends. For example: -# -# * this is a list with three paragraphs in -# the first item. This is the first paragraph. -# -# And this is the second paragraph. -# -# 1. This is an indented, numbered list. -# 2. This is the second item in that list -# -# This is the third conventional paragraph in the -# first list item. -# -# * This is the second item in the original list -# -# produces: -# -# * this is a list with three paragraphs in -# the first item. This is the first paragraph. -# -# And this is the second paragraph. -# -# 1. This is an indented, numbered list. -# 2. This is the second item in that list -# -# This is the third conventional paragraph in the -# first list item. -# -# * This is the second item in the original list -# -# === Labeled Lists -# -# You can also construct labeled lists, sometimes called description -# or definition lists. Do this by putting the label in square brackets -# and indenting the list body: -# -# [cat] a small furry mammal -# that seems to sleep a lot -# -# [ant] a little insect that is known -# to enjoy picnics -# -# produces: -# -# [cat] a small furry mammal -# that seems to sleep a lot -# -# [ant] a little insect that is known -# to enjoy picnics -# -# If you want the list bodies to line up to the left of the labels, -# use two colons: -# -# cat:: a small furry mammal -# that seems to sleep a lot -# -# ant:: a little insect that is known -# to enjoy picnics -# -# produces: -# -# cat:: a small furry mammal -# that seems to sleep a lot -# -# ant:: a little insect that is known -# to enjoy picnics -# -# Notice that blank lines right after the label are ignored in labeled lists: -# -# [one] -# -# definition 1 -# -# [two] -# -# definition 2 -# -# produces the same output as -# -# [one] definition 1 -# [two] definition 2 -# -# -# === Lists and Verbatim -# -# If you want to introduce a verbatim section right after a list, it has to be -# less indented than the list item bodies, but more indented than the list -# label, letter, digit or bullet. For instance: -# -# * point 1 -# -# * point 2, first paragraph -# -# point 2, second paragraph -# verbatim text inside point 2 -# point 2, third paragraph -# verbatim text outside of the list (the list is therefore closed) -# regular paragraph after the list -# -# produces: -# -# * point 1 -# -# * point 2, first paragraph -# -# point 2, second paragraph -# verbatim text inside point 2 -# point 2, third paragraph -# verbatim text outside of the list (the list is therefore closed) -# regular paragraph after the list -# -# == Text Markup -# -# === Bold, Italic, Typewriter Text -# -# You can use markup within text (except verbatim) to change the -# appearance of parts of that text. Out of the box, RDoc::Markup -# supports word-based and general markup. -# -# Word-based markup uses flag characters around individual words: -# -# \*_word_\*:: displays _word_ in a *bold* font -# \__word_\_:: displays _word_ in an _emphasized_ font -# \+_word_\+:: displays _word_ in a +code+ font -# -# General markup affects text between a start delimiter and an end -# delimiter. Not surprisingly, these delimiters look like HTML markup. -# -# \_text_:: displays _text_ in a *bold* font -# \_text_:: displays _text_ in an _emphasized_ font -# (alternate tag: \) -# \_text_\:: displays _text_ in a +code+ font -# (alternate tag: \) -# -# Unlike conventional Wiki markup, general markup can cross line -# boundaries. You can turn off the interpretation of markup by -# preceding the first character with a backslash (see Escaping -# Text Markup, below). -# -# === Links -# -# Links to starting with +http:+, +https:+, +mailto:+, +ftp:+ or +www.+ -# are recognized. An HTTP url that references an external image is converted -# into an inline image element. -# -# Classes and methods will be automatically linked to their definition. For -# example, RDoc::Markup will link to this documentation. By default -# methods will only be automatically linked if they contain an _ (all -# methods can be automatically linked through the --hyperlink-all -# command line option). -# -# Single-word methods can be linked by using the # character for -# instance methods or :: for class methods. For example, -# #convert links to #convert. A class or method may be combined like -# RDoc::Markup#convert. -# -# A heading inside the documentation can be linked by following the class -# or method by an @ then the heading name. -# RDoc::Markup@Links will link to this section like this: -# RDoc::Markup@Links. Spaces in headings with multiple words must be escaped -# with + like RDoc::Markup@Escaping+Text+Markup. -# Punctuation and other special characters must be escaped like CGI.escape. -# -# The @ can also be used to link to sections. If a section and a -# heading share the same name the section is preferred for the link. -# -# Links can also be of the form label[url], in which case +label+ is -# used in the displayed text, and +url+ is used as the target. If +label+ -# contains multiple words, put it in braces: {multi word label}[url]. -# The +url+ may be an +http:+-type link or a cross-reference to a class, -# module or method with a label. -# -# Links with the rdoc-image: scheme will create an image tag for -# HTML output. Only fully-qualified URLs are supported. -# -# Links with the rdoc-ref: scheme will link to the referenced class, -# module, method, file, etc. If the referenced item is does not exist -# no link will be generated and rdoc-ref: will be removed from the -# resulting text. -# -# Links starting with rdoc-label:label_name will link to the -# +label_name+. You can create a label for the current link (for -# bidirectional links) by supplying a name for the current link like -# rdoc-label:label-other:label-mine. -# -# Links starting with +link:+ refer to local files whose path is relative to -# the --op directory. Use rdoc-ref: instead of -# link: to link to files generated by RDoc as the link target may -# be different across RDoc generators. -# -# Example links: -# -# https://github.com/ruby/rdoc -# mailto:user@example.com -# {RDoc Documentation}[http://rdoc.rubyforge.org] -# {RDoc Markup}[rdoc-ref:RDoc::Markup] +# See RDoc::MarkupReference. # # === Escaping Text Markup # diff --git a/lib/rdoc/markup/parser.rb b/lib/rdoc/markup/parser.rb index 1b54a519d1292a..0029df7e65e7f9 100644 --- a/lib/rdoc/markup/parser.rb +++ b/lib/rdoc/markup/parser.rb @@ -287,6 +287,12 @@ def build_verbatim margin line << ' ' * indent when :BREAK, :TEXT then line << data + when :BLOCKQUOTE then + line << '>>>' + peek_type, _, peek_column = peek_token + if peek_type != :NEWLINE and peek_column + line << ' ' * (peek_column - column - 3) + end else # *LIST_TOKENS list_marker = case type when :BULLET then data @@ -372,11 +378,8 @@ def parse parent, indent = 0 unget parse_text parent, indent when :BLOCKQUOTE then - type, _, column = get - if type == :NEWLINE - type, _, column = get - end - unget if type + nil while (type, = get; type) and type != :NEWLINE + _, _, column, = peek_token bq = RDoc::Markup::BlockQuote.new p :blockquote_start => [data, column] if @debug parse bq, column @@ -544,7 +547,10 @@ def tokenize input [:NOTE, @s[1], *pos] # >>> followed by end of line => :BLOCKQUOTE when @s.scan(/>>> *(\w+)?$/) then - [:BLOCKQUOTE, @s[1], *pos] + if word = @s[1] + @s.unscan(word) + end + [:BLOCKQUOTE, word, *pos] # anything else: :TEXT else @s.scan(/(.*?)( )?\r?$/) diff --git a/lib/rdoc/rdoc.gemspec b/lib/rdoc/rdoc.gemspec index 547a67b04bb8de..3c96f7deb11e51 100644 --- a/lib/rdoc/rdoc.gemspec +++ b/lib/rdoc/rdoc.gemspec @@ -38,16 +38,12 @@ RDoc includes the +rdoc+ and +ri+ tools for generating and displaying documentat "CVE-2013-0256.rdoc", "ExampleMarkdown.md", "ExampleRDoc.rdoc", - "Gemfile", "History.rdoc", "LEGAL.rdoc", "LICENSE.rdoc", "README.rdoc", "RI.rdoc", - "Rakefile", "TODO.rdoc", - "bin/console", - "bin/setup", "exe/rdoc", "exe/ri", "lib/rdoc.rb", @@ -223,7 +219,6 @@ RDoc includes the +rdoc+ and +ri+ tools for generating and displaying documentat "lib/rdoc/top_level.rb", "lib/rdoc/version.rb", "man/ri.1", - "rdoc.gemspec", ] # files from .gitignore s.files << "lib/rdoc/rd/block_parser.rb" << "lib/rdoc/rd/inline_parser.rb" << "lib/rdoc/markdown.rb" << "lib/rdoc/markdown/literals.rb" diff --git a/lib/rubygems.rb b/lib/rubygems.rb index e59cd26870b3ea..b21f00acc74b90 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -1010,7 +1010,7 @@ def self.java_platform? # Is this platform Solaris? def self.solaris_platform? - RUBY_PLATFORM =~ /solaris/ + RUBY_PLATFORM.include?("solaris") end ## diff --git a/lib/rubygems/commands/rdoc_command.rb b/lib/rubygems/commands/rdoc_command.rb index 17ad6f836bea94..a998a9704cb3ed 100644 --- a/lib/rubygems/commands/rdoc_command.rb +++ b/lib/rubygems/commands/rdoc_command.rb @@ -86,8 +86,9 @@ def execute begin doc.generate rescue Errno::ENOENT => e - e.message =~ / - / - alert_error "Unable to document #{spec.full_name}, #{$'} is missing, skipping" + match = / - /.match(e.message) + alert_error "Unable to document #{spec.full_name}, " \ + " #{match.post_match} is missing, skipping" terminate_interaction 1 if specs.length == 1 end end diff --git a/lib/rubygems/defaults.rb b/lib/rubygems/defaults.rb index d27f286265c8ff..b805ef91740803 100644 --- a/lib/rubygems/defaults.rb +++ b/lib/rubygems/defaults.rb @@ -171,7 +171,7 @@ def self.default_path def self.default_exec_format exec_format = RbConfig::CONFIG["ruby_install_name"].sub("ruby", "%s") rescue "%s" - unless exec_format =~ /%s/ + unless exec_format.include?("%s") raise Gem::Exception, "[BUG] invalid exec_format #{exec_format.inspect}, no %s" end diff --git a/lib/rubygems/ext/builder.rb b/lib/rubygems/ext/builder.rb index c5a03806b9607b..b46f9b5cd5fa8f 100644 --- a/lib/rubygems/ext/builder.rb +++ b/lib/rubygems/ext/builder.rb @@ -26,7 +26,7 @@ def self.make(dest_path, results, make_dir = Dir.pwd, sitedir = nil) RbConfig::CONFIG["configure_args"] =~ /with-make-prog\=(\w+)/ make_program_name = ENV["MAKE"] || ENV["make"] || $1 unless make_program_name - make_program_name = (/mswin/ =~ RUBY_PLATFORM) ? "nmake" : "make" + make_program_name = (RUBY_PLATFORM.include?("mswin")) ? "nmake" : "make" end make_program = Shellwords.split(make_program_name) diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb index 52307f6d930d80..b764f21a4f9537 100644 --- a/lib/rubygems/installer.rb +++ b/lib/rubygems/installer.rb @@ -234,8 +234,8 @@ def check_executable_overwrite(filename) # :nodoc: io.gets # blankline # TODO detect a specially formatted comment instead of trying - # to run a regexp against Ruby code. - next unless io.gets =~ /This file was generated by RubyGems/ + # to find a string inside Ruby code. + next unless io.gets.to_s.include?("This file was generated by RubyGems") ruby_executable = true existing = io.read.slice(%r{ @@ -490,15 +490,7 @@ def generate_bin # :nodoc: spec.executables.each do |filename| filename.tap(&Gem::UNTAINT) bin_path = File.join gem_dir, spec.bindir, filename - - unless File.exist? bin_path - if File.symlink? bin_path - alert_warning "`#{bin_path}` is dangling symlink pointing to `#{File.readlink bin_path}`" - else - alert_warning "`#{bin_path}` does not exist, maybe `gem pristine #{spec.name}` will fix it?" - end - next - end + next unless File.exist? bin_path mode = File.stat(bin_path).mode dir_mode = options[:prog_mode] || (mode | 0111) diff --git a/lib/rubygems/package.rb b/lib/rubygems/package.rb index 1e87837b0e9009..77f9f282d8fb79 100644 --- a/lib/rubygems/package.rb +++ b/lib/rubygems/package.rb @@ -409,18 +409,23 @@ def extract_files(destination_dir, pattern = "*") def extract_tar_gz(io, destination_dir, pattern = "*") # :nodoc: directories = [] + symlinks = [] + open_tar_gz io do |tar| tar.each do |entry| - next unless File.fnmatch pattern, entry.full_name, File::FNM_DOTMATCH + full_name = entry.full_name + next unless File.fnmatch pattern, full_name, File::FNM_DOTMATCH - destination = install_location entry.full_name, destination_dir + destination = install_location full_name, destination_dir if entry.symlink? link_target = entry.header.linkname real_destination = link_target.start_with?("/") ? link_target : File.expand_path(link_target, File.dirname(destination)) - raise Gem::Package::SymlinkError.new(entry.full_name, real_destination, destination_dir) unless + raise Gem::Package::SymlinkError.new(full_name, real_destination, destination_dir) unless normalize_path(real_destination).start_with? normalize_path(destination_dir + "/") + + symlinks << [full_name, link_target, destination, real_destination] end FileUtils.rm_rf destination @@ -444,12 +449,18 @@ def extract_tar_gz(io, destination_dir, pattern = "*") # :nodoc: FileUtils.chmod file_mode(entry.header.mode), destination end if entry.file? - File.symlink(entry.header.linkname, destination) if entry.symlink? - verbose destination end end + symlinks.each do |name, target, destination, real_destination| + if File.exist?(real_destination) + File.symlink(target, destination) + else + alert_warning "#{@spec.full_name} ships with a dangling symlink named #{name} pointing to missing #{target} file. Ignoring" + end + end + if dir_mode File.chmod(dir_mode, *directories) end diff --git a/lib/rubygems/resolver/index_specification.rb b/lib/rubygems/resolver/index_specification.rb index e8c3b35f7e6314..0fc758dfd3ac5c 100644 --- a/lib/rubygems/resolver/index_specification.rb +++ b/lib/rubygems/resolver/index_specification.rb @@ -21,7 +21,8 @@ def initialize(set, name, version, source, platform) @name = name @version = version @source = source - @platform = platform.to_s + @platform = Gem::Platform.new(platform.to_s) + @original_platform = platform.to_s @spec = nil end @@ -91,7 +92,7 @@ def pretty_print(q) # :nodoc: def spec # :nodoc: @spec ||= begin - tuple = Gem::NameTuple.new @name, @version, @platform + tuple = Gem::NameTuple.new @name, @version, @original_platform @source.fetch_spec tuple end diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb index f2e274002641e5..28ad176b535578 100644 --- a/lib/rubygems/specification.rb +++ b/lib/rubygems/specification.rb @@ -2653,6 +2653,8 @@ def validate_permissions def version=(version) @version = Gem::Version.create(version) + return if @version.nil? + # skip to set required_ruby_version when pre-released rubygems. # It caused to raise CircularDependencyError if @version.prerelease? && (@name.nil? || @name.strip != "rubygems") diff --git a/lib/rubygems/validator.rb b/lib/rubygems/validator.rb index 60104a34d5352c..1609924607d7b8 100644 --- a/lib/rubygems/validator.rb +++ b/lib/rubygems/validator.rb @@ -26,7 +26,7 @@ def find_files_for_gem(gem_directory) Find.find gem_directory do |file_name| fn = file_name[gem_directory.size..file_name.size - 1].sub(/^\//, "") installed_files << fn unless - fn =~ /CVS/ || fn.empty? || File.directory?(file_name) + fn.empty? || fn.include?("CVS") || File.directory?(file_name) end installed_files diff --git a/lib/rubygems/version.rb b/lib/rubygems/version.rb index 03ae5ca17eb13b..bb41374ffc3d02 100644 --- a/lib/rubygems/version.rb +++ b/lib/rubygems/version.rb @@ -171,9 +171,7 @@ def version # True if the +version+ string matches RubyGems' requirements. def self.correct?(version) - unless Gem::Deprecate.skip - warn "nil versions are discouraged and will be deprecated in Rubygems 4" if version.nil? - end + nil_versions_are_discouraged! if version.nil? !!(version.to_s =~ ANCHORED_VERSION_PATTERN) end @@ -190,6 +188,8 @@ def self.create(input) if self === input # check yourself before you wreck yourself input elsif input.nil? + nil_versions_are_discouraged! + nil else new input @@ -206,6 +206,14 @@ def self.new(version) # :nodoc: @@all[version] ||= super end + def self.nil_versions_are_discouraged! + unless Gem::Deprecate.skip + warn "nil versions are discouraged and will be deprecated in Rubygems 4" + end + end + + private_class_method :nil_versions_are_discouraged! + ## # Constructs a Version from the +version+ string. A version string is a # series of digits or ASCII letters separated by dots. diff --git a/lib/time.rb b/lib/time.rb index bd20a1a8e9b79b..43c4d802e5b603 100644 --- a/lib/time.rb +++ b/lib/time.rb @@ -701,7 +701,7 @@ def httpdate # # If self is a UTC time, Z is used as TZD. [+-]hh:mm is used otherwise. # - # +fractional_digits+ specifies a number of digits to use for fractional + # +fraction_digits+ specifies a number of digits to use for fractional # seconds. Its default value is 0. # # require 'time' diff --git a/load.c b/load.c index e3daea7d7b25ac..62b9b2d9bdd926 100644 --- a/load.c +++ b/load.c @@ -54,7 +54,7 @@ rb_construct_expanded_load_path(rb_vm_t *vm, enum expand_type type, int *has_rel VALUE ary; long i; - ary = rb_ary_tmp_new(RARRAY_LEN(load_path)); + ary = rb_ary_hidden_new(RARRAY_LEN(load_path)); for (i = 0; i < RARRAY_LEN(load_path); ++i) { VALUE path, as_str, expanded_path; int is_string, non_cache; @@ -1427,15 +1427,15 @@ Init_load(void) rb_alias_variable(rb_intern_const("$-I"), id_load_path); rb_alias_variable(rb_intern_const("$LOAD_PATH"), id_load_path); vm->load_path = rb_ary_new(); - vm->expanded_load_path = rb_ary_tmp_new(0); - vm->load_path_snapshot = rb_ary_tmp_new(0); + vm->expanded_load_path = rb_ary_hidden_new(0); + vm->load_path_snapshot = rb_ary_hidden_new(0); vm->load_path_check_cache = 0; rb_define_singleton_method(vm->load_path, "resolve_feature_path", rb_resolve_feature_path, 1); rb_define_virtual_variable("$\"", get_LOADED_FEATURES, 0); rb_define_virtual_variable("$LOADED_FEATURES", get_LOADED_FEATURES, 0); vm->loaded_features = rb_ary_new(); - vm->loaded_features_snapshot = rb_ary_tmp_new(0); + vm->loaded_features_snapshot = rb_ary_hidden_new(0); vm->loaded_features_index = st_init_numtable(); vm->loaded_features_realpaths = rb_hash_new(); rb_obj_hide(vm->loaded_features_realpaths); @@ -1448,6 +1448,6 @@ Init_load(void) rb_define_global_function("autoload", rb_f_autoload, 2); rb_define_global_function("autoload?", rb_f_autoload_p, -1); - ruby_dln_librefs = rb_ary_tmp_new(0); + ruby_dln_librefs = rb_ary_hidden_new(0); rb_gc_register_mark_object(ruby_dln_librefs); } diff --git a/marshal.c b/marshal.c index 3bca956a09c9e5..43102a54c5b78b 100644 --- a/marshal.c +++ b/marshal.c @@ -1763,7 +1763,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ { VALUE path = r_unique(arg); VALUE m = rb_path_to_class(path); - if (NIL_P(extmod)) extmod = rb_ary_tmp_new(0); + if (NIL_P(extmod)) extmod = rb_ary_hidden_new(0); if (RB_TYPE_P(m, T_CLASS)) { /* prepended */ VALUE c; diff --git a/missing/flock.c b/missing/flock.c index 9daf1c38ccc4ba..0b76961762597e 100644 --- a/missing/flock.c +++ b/missing/flock.c @@ -5,9 +5,11 @@ #elif defined __wasi__ #include -int flock(int fd, int operation) { - errno = EINVAL; - return -1; +int +flock(int fd, int operation) +{ + errno = EINVAL; + return -1; } #elif defined HAVE_FCNTL && defined HAVE_FCNTL_H diff --git a/mjit.c b/mjit.c index da3fd9d61e3996..98f4af3d18fa71 100644 --- a/mjit.c +++ b/mjit.c @@ -811,8 +811,16 @@ start_compiling_c_to_so(const char *c_file, const char *so_file) # endif c_file, NULL }; - char **args = form_args(7, CC_LDSHARED_ARGS, CC_CODEFLAG_ARGS, cc_added_args, - so_args, CC_LIBS, CC_DLDFLAGS_ARGS, CC_LINKER_ARGS); + +# if defined(__MACH__) + extern VALUE rb_libruby_selfpath; + const char *loader_args[] = {"-bundle_loader", StringValuePtr(rb_libruby_selfpath), NULL}; +# else + const char *loader_args[] = {NULL}; +# endif + + char **args = form_args(8, CC_LDSHARED_ARGS, CC_CODEFLAG_ARGS, cc_added_args, + so_args, loader_args, CC_LIBS, CC_DLDFLAGS_ARGS, CC_LINKER_ARGS); if (args == NULL) return -1; rb_vm_t *vm = GET_VM(); @@ -1501,7 +1509,8 @@ create_unit(const rb_iseq_t *iseq) unit->id = current_unit_num++; if (iseq == NULL) { // Compact unit unit->compact_p = true; - } else { // Normal unit + } + else { // Normal unit unit->iseq = (rb_iseq_t *)iseq; ISEQ_BODY(iseq)->jit_unit = unit; } diff --git a/node.c b/node.c index a10d5122c37147..483e7fa8fbd0ed 100644 --- a/node.c +++ b/node.c @@ -1138,6 +1138,7 @@ rb_node_init(NODE *n, enum node_type type, VALUE a0, VALUE a1, VALUE a2) n->nd_loc.beg_pos.column = 0; n->nd_loc.end_pos.lineno = 0; n->nd_loc.end_pos.column = 0; + n->node_id = -1; } typedef struct node_buffer_elem_struct { diff --git a/object.c b/object.c index 3a8a07736a66fc..d1743b554ba4eb 100644 --- a/object.c +++ b/object.c @@ -1623,16 +1623,19 @@ rb_class_inherited_p(VALUE mod, VALUE arg) return RCLASS_SUPERCLASSES(mod)[arg_depth] == arg ? Qtrue : Qnil; - } else if (arg_depth > mod_depth) { + } + else if (arg_depth > mod_depth) { // check if mod > arg return RCLASS_SUPERCLASSES(arg)[mod_depth] == mod ? Qfalse : Qnil; - } else { + } + else { // Depths match, and we know they aren't equal: no relation return Qnil; } - } else { + } + else { if (!CLASS_OR_MODULE_P(arg) && !RB_TYPE_P(arg, T_ICLASS)) { rb_raise(rb_eTypeError, "compared with non class/module"); } @@ -2025,7 +2028,8 @@ rb_class_superclass(VALUE klass) if (!super) { if (klass == rb_cBasicObject) return Qnil; rb_raise(rb_eTypeError, "uninitialized class"); - } else { + } + else { super = RCLASS_SUPERCLASSES(klass)[RCLASS_SUPERCLASS_DEPTH(klass) - 1]; RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS)); return super; diff --git a/proc.c b/proc.c index 1fa21a59ec2f46..a525562230b3c8 100644 --- a/proc.c +++ b/proc.c @@ -1491,7 +1491,7 @@ rb_sym_to_proc(VALUE sym) ID id; if (!sym_proc_cache) { - sym_proc_cache = rb_ary_tmp_new(SYM_PROC_CACHE_SIZE * 2); + sym_proc_cache = rb_ary_hidden_new(SYM_PROC_CACHE_SIZE * 2); rb_gc_register_mark_object(sym_proc_cache); rb_ary_store(sym_proc_cache, SYM_PROC_CACHE_SIZE*2 - 1, Qnil); } diff --git a/ractor.rb b/ractor.rb index ef36b2937f6fc2..953d3ceddc197f 100644 --- a/ractor.rb +++ b/ractor.rb @@ -699,7 +699,7 @@ def take def inspect loc = __builtin_cexpr! %q{ RACTOR_PTR(self)->loc } name = __builtin_cexpr! %q{ RACTOR_PTR(self)->name } - id = __builtin_cexpr! %q{ INT2FIX(rb_ractor_id(RACTOR_PTR(self))) } + id = __builtin_cexpr! %q{ UINT2NUM(rb_ractor_id(RACTOR_PTR(self))) } status = __builtin_cexpr! %q{ rb_str_new2(ractor_status_str(RACTOR_PTR(self)->status_)) } diff --git a/ractor_core.h b/ractor_core.h index 32ae9ab0138191..412971decfc418 100644 --- a/ractor_core.h +++ b/ractor_core.h @@ -273,7 +273,7 @@ rb_ractor_set_current_ec_(rb_ractor_t *cr, rb_execution_context_t *ec, const cha #else native_tls_set(ruby_current_ec_key, ec); #endif - RUBY_DEBUG_LOG2(file, line, "ec:%p->%p", cr->threads.running_ec, ec); + RUBY_DEBUG_LOG2(file, line, "ec:%p->%p", (void *)cr->threads.running_ec, (void *)ec); VM_ASSERT(cr->threads.running_ec != ec); cr->threads.running_ec = ec; } diff --git a/re.c b/re.c index 7642dc36510fde..a633d1bb7b312d 100644 --- a/re.c +++ b/re.c @@ -1735,9 +1735,7 @@ rb_reg_search_set_match(VALUE re, VALUE str, long pos, int reverse, int set_back } match = match_alloc(rb_cMatch); - int copy_err = rb_reg_region_copy(RMATCH_REGS(match), regs); - onig_region_free(regs, 0); - if (copy_err) rb_memerror(); + memcpy(RMATCH_REGS(match), regs, sizeof(struct re_registers)); if (set_backref_str) { RMATCH(match)->str = rb_str_new4(str); diff --git a/ruby.c b/ruby.c index 87876d5160ff34..9b9bfb54c7795b 100644 --- a/ruby.c +++ b/ruby.c @@ -22,7 +22,7 @@ # include #endif -#if defined(LOAD_RELATIVE) && defined(HAVE_DLADDR) +#if (defined(LOAD_RELATIVE) || defined(__MACH__)) && defined(HAVE_DLADDR) # include #endif @@ -534,7 +534,7 @@ str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to) void ruby_init_loadpath(void); -#if defined(LOAD_RELATIVE) +#if defined(LOAD_RELATIVE) || defined(__MACH__) static VALUE runtime_libruby_path(void) { @@ -615,6 +615,10 @@ runtime_libruby_path(void) #define INITIAL_LOAD_PATH_MARK rb_intern_const("@gem_prelude_index") VALUE ruby_archlibdir_path, ruby_prefix_path; +#if defined(__MACH__) +// A path to libruby.dylib itself or where it's statically linked to. +VALUE rb_libruby_selfpath; +#endif void ruby_init_loadpath(void) @@ -622,6 +626,14 @@ ruby_init_loadpath(void) VALUE load_path, archlibdir = 0; ID id_initial_load_path_mark; const char *paths = ruby_initial_load_paths; +#if defined(LOAD_RELATIVE) || defined(__MACH__) + VALUE libruby_path = runtime_libruby_path(); +# if defined(__MACH__) + rb_libruby_selfpath = libruby_path; + rb_gc_register_address(&rb_libruby_selfpath); +# endif +#endif + #if defined LOAD_RELATIVE #if !defined ENABLE_MULTIARCH # define RUBY_ARCH_PATH "" @@ -635,7 +647,7 @@ ruby_init_loadpath(void) size_t baselen; const char *p; - sopath = runtime_libruby_path(); + sopath = libruby_path; libpath = RSTRING_PTR(sopath); p = strrchr(libpath, '/'); @@ -725,7 +737,7 @@ add_modules(VALUE *req_list, const char *mod) VALUE feature; if (!list) { - *req_list = list = rb_ary_tmp_new(0); + *req_list = list = rb_ary_hidden_new(0); } feature = rb_str_cat_cstr(rb_str_tmp_new(0), mod); rb_ary_push(list, feature); diff --git a/spec/bundler/bundler/gem_helper_spec.rb b/spec/bundler/bundler/gem_helper_spec.rb index 5cd79de620321d..7d955007ab935c 100644 --- a/spec/bundler/bundler/gem_helper_spec.rb +++ b/spec/bundler/bundler/gem_helper_spec.rb @@ -11,6 +11,7 @@ before(:each) do global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__LINTER" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__CHANGELOG" => "false" + sys_exec("git config --global init.defaultBranch main") bundle "gem #{app_name}" prepare_gemspec(app_gemspec_path) end @@ -295,7 +296,7 @@ def sha512_hexdigest(path) mock_confirm_message "Tagged v#{app_version}." mock_confirm_message "Pushed git commits and release tag." - sys_exec("git push -u origin master", :dir => app_path) + sys_exec("git push -u origin main", :dir => app_path) end it "calls rubygem_push with proper arguments" do @@ -336,7 +337,7 @@ def sha512_hexdigest(path) mock_build_message app_name, app_version mock_confirm_message "Pushed git commits and release tag." - sys_exec("git push -u origin master", :dir => app_path) + sys_exec("git push -u origin main", :dir => app_path) expect(subject).to receive(:rubygem_push).with(app_gem_path.to_s) end diff --git a/spec/bundler/bundler/ruby_version_spec.rb b/spec/bundler/bundler/ruby_version_spec.rb index 3e3850031c2463..f1df12294dbb79 100644 --- a/spec/bundler/bundler/ruby_version_spec.rb +++ b/spec/bundler/bundler/ruby_version_spec.rb @@ -427,9 +427,8 @@ end describe "#version" do - it "should return a copy of the value of RUBY_VERSION" do - expect(subject.versions).to eq([RUBY_VERSION]) - expect(subject.versions.first).to_not be(RUBY_VERSION) + it "should return the value of Gem.ruby_version as a string" do + expect(subject.versions).to eq([Gem.ruby_version.to_s]) end end @@ -446,13 +445,12 @@ describe "#engine_version" do context "engine is ruby" do before do - stub_const("RUBY_ENGINE_VERSION", "2.2.4") + allow(Gem).to receive(:ruby_version).and_return(Gem::Version.new("2.2.4")) stub_const("RUBY_ENGINE", "ruby") end - it "should return a copy of the value of RUBY_ENGINE_VERSION" do + it "should return the value of Gem.ruby_version as a string" do expect(bundler_system_ruby_version.engine_versions).to eq(["2.2.4"]) - expect(bundler_system_ruby_version.engine_versions.first).to_not be(RUBY_ENGINE_VERSION) end end diff --git a/spec/bundler/cache/git_spec.rb b/spec/bundler/cache/git_spec.rb index b88993e9b1b1fb..7ea23cd312f321 100644 --- a/spec/bundler/cache/git_spec.rb +++ b/spec/bundler/cache/git_spec.rb @@ -15,7 +15,7 @@ RSpec.describe "bundle cache with git" do it "copies repository to vendor cache and uses it" do git = build_git "foo" - ref = git.ref_for("master", 11) + ref = git.ref_for("main", 11) install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" @@ -34,7 +34,7 @@ it "copies repository to vendor cache and uses it even when configured with `path`" do git = build_git "foo" - ref = git.ref_for("master", 11) + ref = git.ref_for("main", 11) install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" @@ -72,7 +72,7 @@ it "tracks updates" do git = build_git "foo" - old_ref = git.ref_for("master", 11) + old_ref = git.ref_for("main", 11) install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" @@ -86,7 +86,7 @@ s.write "lib/foo.rb", "puts :CACHE" end - ref = git.ref_for("master", 11) + ref = git.ref_for("main", 11) expect(ref).not_to eq(old_ref) bundle "update", :all => true @@ -103,7 +103,7 @@ it "tracks updates when specifying the gem" do git = build_git "foo" - old_ref = git.ref_for("master", 11) + old_ref = git.ref_for("main", 11) install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" @@ -117,7 +117,7 @@ s.write "lib/foo.rb", "puts :CACHE" end - ref = git.ref_for("master", 11) + ref = git.ref_for("main", 11) expect(ref).not_to eq(old_ref) bundle "update foo" @@ -132,11 +132,11 @@ it "uses the local repository to generate the cache" do git = build_git "foo" - ref = git.ref_for("master", 11) + ref = git.ref_for("main", 11) gemfile <<-G source "#{file_uri_for(gem_repo1)}" - gem "foo", :git => '#{lib_path("foo-invalid")}', :branch => :master + gem "foo", :git => '#{lib_path("foo-invalid")}', :branch => :main G bundle %(config set local.foo #{lib_path("foo-1.0")}) @@ -172,7 +172,7 @@ end G - ref = git.ref_for("master", 11) + ref = git.ref_for("main", 11) bundle "config set cache_all true" bundle :cache @@ -196,7 +196,7 @@ bundle "config set cache_all true" bundle :cache - ref = git.ref_for("master", 11) + ref = git.ref_for("main", 11) gemspec = bundled_app("vendor/cache/foo-1.0-#{ref}/foo.gemspec").read expect(gemspec).to_not match("`echo bob`") end diff --git a/spec/bundler/commands/info_spec.rb b/spec/bundler/commands/info_spec.rb index 74943703a20d91..e4b970eb34c15e 100644 --- a/spec/bundler/commands/info_spec.rb +++ b/spec/bundler/commands/info_spec.rb @@ -163,10 +163,10 @@ expect(the_bundle).to include_gems "foo 1.0" bundle "info foo" - expect(out).to include("foo (1.0 #{@git.ref_for("master", 6)}") + expect(out).to include("foo (1.0 #{@git.ref_for("main", 6)}") end - it "prints out branch names other than master" do + it "prints out branch names other than main" do update_git "foo", :branch => "omg" do |s| s.write "lib/foo.rb", "FOO = '1.0.omg'" end diff --git a/spec/bundler/commands/install_spec.rb b/spec/bundler/commands/install_spec.rb index 57cff4e3b3e98a..7bf36ee0204422 100644 --- a/spec/bundler/commands/install_spec.rb +++ b/spec/bundler/commands/install_spec.rb @@ -522,14 +522,14 @@ ruby '~> 1.2' source "#{file_uri_for(gem_repo1)}" G - expect(err).to include("Your Ruby version is #{RUBY_VERSION}, but your Gemfile specified ~> 1.2") + expect(err).to include("Your Ruby version is #{Gem.ruby_version}, but your Gemfile specified ~> 1.2") end end context "and using a supported Ruby version" do before do install_gemfile <<-G - ruby '~> #{RUBY_VERSION}' + ruby '~> #{Gem.ruby_version}' source "#{file_uri_for(gem_repo1)}" G end @@ -555,7 +555,7 @@ it "updates Gemfile.lock with updated yet still compatible ruby version" do install_gemfile <<-G - ruby '~> #{RUBY_VERSION[0..2]}' + ruby '~> #{current_ruby_minor}' source "#{file_uri_for(gem_repo1)}" G @@ -913,7 +913,7 @@ def run gemfile <<-G source "https://gem.repo4" - ruby "#{RUBY_VERSION}" + ruby "#{Gem.ruby_version}" gem "loofah", "~> 2.12.0" G @@ -1000,6 +1000,50 @@ def run end end + context "with only option" do + before do + bundle "config set only a:b" + end + + it "installs only gems of the specified groups" do + install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + gem "rails" + gem "rack", group: :a + gem "rake", group: :b + gem "yard", group: :c + G + + expect(out).to include("Installing rack") + expect(out).to include("Installing rake") + expect(out).not_to include("Installing yard") + end + end + + context "with --prefer-local flag" do + before do + build_repo4 do + build_gem "foo", "1.0.1" + build_gem "foo", "1.0.0" + build_gem "bar", "1.0.0" + end + + system_gems "foo-1.0.0", :path => default_bundle_path, :gem_repo => gem_repo4 + end + + it "fetches remote sources only when not available locally" do + install_gemfile <<-G, :"prefer-local" => true, :verbose => true + source "#{file_uri_for(gem_repo4)}" + + gem "foo" + gem "bar" + G + + expect(out).to include("Using foo 1.0.0").and include("Fetching bar 1.0.0").and include("Installing bar 1.0.0") + expect(last_command).to be_success + end + end + context "with a symlinked configured as bundle path and a gem with symlinks" do before do symlinked_bundled_app = tmp("bundled_app-symlink") diff --git a/spec/bundler/commands/lock_spec.rb b/spec/bundler/commands/lock_spec.rb index b20a6ded43d10f..b314169a9850a7 100644 --- a/spec/bundler/commands/lock_spec.rb +++ b/spec/bundler/commands/lock_spec.rb @@ -541,11 +541,9 @@ def read_lockfile(file = "Gemfile.lock") end it "respects lower bound ruby requirements" do - skip "this spec does not work with prereleases because their version is actually lower than their reported `RUBY_VERSION`" if RUBY_PATCHLEVEL == -1 - build_repo4 do build_gem "our_private_gem", "0.1.0" do |s| - s.required_ruby_version = ">= #{RUBY_VERSION}" + s.required_ruby_version = ">= #{Gem.ruby_version}" end end diff --git a/spec/bundler/commands/open_spec.rb b/spec/bundler/commands/open_spec.rb index 53dc35c2c772df..85f15176b4092d 100644 --- a/spec/bundler/commands/open_spec.rb +++ b/spec/bundler/commands/open_spec.rb @@ -36,7 +36,7 @@ it "does not blow up if the gem to open does not have a Gemfile" do git = build_git "foo" - ref = git.ref_for("master", 11) + ref = git.ref_for("main", 11) install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" diff --git a/spec/bundler/commands/outdated_spec.rb b/spec/bundler/commands/outdated_spec.rb index d0209022a254fd..e084af85d791bb 100644 --- a/spec/bundler/commands/outdated_spec.rb +++ b/spec/bundler/commands/outdated_spec.rb @@ -604,6 +604,22 @@ def test_group_option(group) expect(out).to end_with(expected_output) end + it "only reports gems that have a newer version that matches the specified dependency version requirements, using --strict alias" do + update_repo2 do + build_gem "activesupport", "3.0" + build_gem "weakling", "0.0.5" + end + + bundle :outdated, :strict => true, :raise_on_error => false + + expected_output = <<~TABLE.strip + Gem Current Latest Requested Groups + weakling 0.0.3 0.0.5 ~> 0.0.1 default + TABLE + + expect(out).to end_with(expected_output) + end + it "doesn't crash when some deps unused on the current platform" do install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" @@ -1098,116 +1114,125 @@ def test_group_option(group) end context "conservative updates" do - context "without --strict" do - before do - build_repo4 do - build_gem "patch", %w[1.0.0 1.0.1] - build_gem "minor", %w[1.0.0 1.0.1 1.1.0] - build_gem "major", %w[1.0.0 1.0.1 1.1.0 2.0.0] - end + before do + build_repo4 do + build_gem "patch", %w[1.0.0 1.0.1] + build_gem "minor", %w[1.0.0 1.0.1 1.1.0] + build_gem "major", %w[1.0.0 1.0.1 1.1.0 2.0.0] + end - # establish a lockfile set to 1.0.0 - install_gemfile <<-G - source "#{file_uri_for(gem_repo4)}" - gem 'patch', '1.0.0' - gem 'minor', '1.0.0' - gem 'major', '1.0.0' - G + # establish a lockfile set to 1.0.0 + install_gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + gem 'patch', '1.0.0' + gem 'minor', '1.0.0' + gem 'major', '1.0.0' + G - # remove 1.4.3 requirement and bar altogether - # to setup update specs below - gemfile <<-G - source "#{file_uri_for(gem_repo4)}" - gem 'patch' - gem 'minor' - gem 'major' - G - end + # remove all version requirements + gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + gem 'patch' + gem 'minor' + gem 'major' + G + end - it "shows nothing when patching and filtering to minor" do - bundle "outdated --patch --filter-minor" + it "shows nothing when patching and filtering to minor" do + bundle "outdated --patch --filter-minor" - expect(out).to end_with("No minor updates to display.") - end + expect(out).to end_with("No minor updates to display.") + end - it "shows all gems when patching and filtering to patch" do - bundle "outdated --patch --filter-patch", :raise_on_error => false + it "shows all gems when patching and filtering to patch" do + bundle "outdated --patch --filter-patch", :raise_on_error => false - expected_output = <<~TABLE.strip - Gem Current Latest Requested Groups - major 1.0.0 1.0.1 >= 0 default - minor 1.0.0 1.0.1 >= 0 default - patch 1.0.0 1.0.1 >= 0 default - TABLE + expected_output = <<~TABLE.strip + Gem Current Latest Requested Groups + major 1.0.0 1.0.1 >= 0 default + minor 1.0.0 1.0.1 >= 0 default + patch 1.0.0 1.0.1 >= 0 default + TABLE - expect(out).to end_with(expected_output) - end + expect(out).to end_with(expected_output) + end - it "shows minor and major when updating to minor and filtering to patch and minor" do - bundle "outdated --minor --filter-minor", :raise_on_error => false + it "shows minor and major when updating to minor and filtering to patch and minor" do + bundle "outdated --minor --filter-minor", :raise_on_error => false - expected_output = <<~TABLE.strip - Gem Current Latest Requested Groups - major 1.0.0 1.1.0 >= 0 default - minor 1.0.0 1.1.0 >= 0 default - TABLE + expected_output = <<~TABLE.strip + Gem Current Latest Requested Groups + major 1.0.0 1.1.0 >= 0 default + minor 1.0.0 1.1.0 >= 0 default + TABLE - expect(out).to end_with(expected_output) - end + expect(out).to end_with(expected_output) + end - it "shows minor when updating to major and filtering to minor with parseable" do - bundle "outdated --major --filter-minor --parseable", :raise_on_error => false + it "shows minor when updating to major and filtering to minor with parseable" do + bundle "outdated --major --filter-minor --parseable", :raise_on_error => false - expect(out).not_to include("patch (newest") - expect(out).to include("minor (newest") - expect(out).not_to include("major (newest") - end + expect(out).not_to include("patch (newest") + expect(out).to include("minor (newest") + expect(out).not_to include("major (newest") end + end - context "with --strict" do - before do - build_repo4 do - build_gem "foo", %w[1.4.3 1.4.4] do |s| - s.add_dependency "bar", "~> 2.0" - end - build_gem "foo", %w[1.4.5 1.5.0] do |s| - s.add_dependency "bar", "~> 2.1" - end - build_gem "foo", %w[1.5.1] do |s| - s.add_dependency "bar", "~> 3.0" - end - build_gem "bar", %w[2.0.3 2.0.4 2.0.5 2.1.0 2.1.1 3.0.0] - build_gem "qux", %w[1.0.0 1.1.0 2.0.0] + context "tricky conservative updates" do + before do + build_repo4 do + build_gem "foo", %w[1.4.3 1.4.4] do |s| + s.add_dependency "bar", "~> 2.0" + end + build_gem "foo", %w[1.4.5 1.5.0] do |s| + s.add_dependency "bar", "~> 2.1" end + build_gem "foo", %w[1.5.1] do |s| + s.add_dependency "bar", "~> 3.0" + end + build_gem "bar", %w[2.0.3 2.0.4 2.0.5 2.1.0 2.1.1 3.0.0] + build_gem "qux", %w[1.0.0 1.1.0 2.0.0] + end - # establish a lockfile set to 1.4.3 - install_gemfile <<-G - source "#{file_uri_for(gem_repo4)}" - gem 'foo', '1.4.3' - gem 'bar', '2.0.3' - gem 'qux', '1.0.0' - G + # establish a lockfile set to 1.4.3 + install_gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + gem 'foo', '1.4.3' + gem 'bar', '2.0.3' + gem 'qux', '1.0.0' + G - # remove 1.4.3 requirement and bar altogether - # to setup update specs below - gemfile <<-G - source "#{file_uri_for(gem_repo4)}" - gem 'foo' - gem 'qux' - G - end + # remove 1.4.3 requirement and bar altogether + # to setup update specs below + gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + gem 'foo' + gem 'qux' + G + end - it "shows gems with --strict updating to patch and filtering to patch" do - bundle "outdated --patch --strict --filter-patch", :raise_on_error => false + it "shows gems updating to patch and filtering to patch" do + bundle "outdated --patch --filter-patch", :raise_on_error => false, :env => { "DEBUG_RESOLVER" => "1" } - expected_output = <<~TABLE.strip - Gem Current Latest Requested Groups - bar 2.0.3 2.0.5 - foo 1.4.3 1.4.4 >= 0 default - TABLE + expected_output = <<~TABLE.strip + Gem Current Latest Requested Groups + bar 2.0.3 2.0.5 + foo 1.4.3 1.4.4 >= 0 default + TABLE - expect(out).to end_with(expected_output) - end + expect(out).to end_with(expected_output) + end + + it "shows gems updating to patch and filtering to patch, in debug mode" do + bundle "outdated --patch --filter-patch", :raise_on_error => false, :env => { "DEBUG" => "1" } + + expected_output = <<~TABLE.strip + Gem Current Latest Requested Groups Path + bar 2.0.3 2.0.5 + foo 1.4.3 1.4.4 >= 0 default + TABLE + + expect(out).to end_with(expected_output) end end diff --git a/spec/bundler/other/platform_spec.rb b/spec/bundler/commands/platform_spec.rb similarity index 97% rename from spec/bundler/other/platform_spec.rb rename to spec/bundler/commands/platform_spec.rb index c157345cab7687..0b964eac8cd255 100644 --- a/spec/bundler/other/platform_spec.rb +++ b/spec/bundler/commands/platform_spec.rb @@ -19,7 +19,7 @@ * #{specific_local_platform} Your Gemfile specifies a Ruby version requirement: -* ruby #{RUBY_VERSION} +* ruby #{Gem.ruby_version} Your current platform satisfies the Ruby version requirement. G @@ -42,7 +42,7 @@ * #{specific_local_platform} Your Gemfile specifies a Ruby version requirement: -* ruby #{RUBY_VERSION}p#{RUBY_PATCHLEVEL} +* #{Bundler::RubyVersion.system.single_version_string} Your current platform satisfies the Ruby version requirement. G @@ -85,7 +85,7 @@ Your Gemfile specifies a Ruby version requirement: * ruby #{not_local_ruby_version} -Your Ruby version is #{RUBY_VERSION}, but your Gemfile specified #{not_local_ruby_version} +Your Ruby version is #{Gem.ruby_version}, but your Gemfile specified #{not_local_ruby_version} G end end @@ -231,7 +231,7 @@ L bundle "platform --ruby" - expect(out).to eq("ruby 1.0.0p127") + expect(out).to eq("ruby 1.0.0") end it "handles when there is a requirement in the gemfile" do @@ -255,18 +255,18 @@ end end - let(:ruby_version_correct) { "ruby \"#{RUBY_VERSION}\", :engine => \"#{local_ruby_engine}\", :engine_version => \"#{local_engine_version}\"" } - let(:ruby_version_correct_engineless) { "ruby \"#{RUBY_VERSION}\"" } + let(:ruby_version_correct) { "ruby \"#{Gem.ruby_version}\", :engine => \"#{local_ruby_engine}\", :engine_version => \"#{local_engine_version}\"" } + let(:ruby_version_correct_engineless) { "ruby \"#{Gem.ruby_version}\"" } let(:ruby_version_correct_patchlevel) { "#{ruby_version_correct}, :patchlevel => '#{RUBY_PATCHLEVEL}'" } let(:ruby_version_incorrect) { "ruby \"#{not_local_ruby_version}\", :engine => \"#{local_ruby_engine}\", :engine_version => \"#{not_local_ruby_version}\"" } - let(:engine_incorrect) { "ruby \"#{RUBY_VERSION}\", :engine => \"#{not_local_tag}\", :engine_version => \"#{RUBY_VERSION}\"" } - let(:engine_version_incorrect) { "ruby \"#{RUBY_VERSION}\", :engine => \"#{local_ruby_engine}\", :engine_version => \"#{not_local_engine_version}\"" } + let(:engine_incorrect) { "ruby \"#{Gem.ruby_version}\", :engine => \"#{not_local_tag}\", :engine_version => \"#{Gem.ruby_version}\"" } + let(:engine_version_incorrect) { "ruby \"#{Gem.ruby_version}\", :engine => \"#{local_ruby_engine}\", :engine_version => \"#{not_local_engine_version}\"" } let(:patchlevel_incorrect) { "#{ruby_version_correct}, :patchlevel => '#{not_local_patchlevel}'" } let(:patchlevel_fixnum) { "#{ruby_version_correct}, :patchlevel => #{RUBY_PATCHLEVEL}1" } def should_be_ruby_version_incorrect expect(exitstatus).to eq(18) - expect(err).to be_include("Your Ruby version is #{RUBY_VERSION}, but your Gemfile specified #{not_local_ruby_version}") + expect(err).to be_include("Your Ruby version is #{Gem.ruby_version}, but your Gemfile specified #{not_local_ruby_version}") end def should_be_engine_incorrect diff --git a/spec/bundler/commands/pristine_spec.rb b/spec/bundler/commands/pristine_spec.rb index fe85e1ecd1439d..9e496dc91a9f89 100644 --- a/spec/bundler/commands/pristine_spec.rb +++ b/spec/bundler/commands/pristine_spec.rb @@ -22,7 +22,7 @@ source "#{file_uri_for(gem_repo2)}" gem "weakling" gem "very_simple_binary" - gem "foo", :git => "#{lib_path("foo")}", :branch => "master" + gem "foo", :git => "#{lib_path("foo")}", :branch => "main" gem "git_with_ext", :git => "#{lib_path("git_with_ext")}" gem "bar", :path => "#{lib_path("bar")}" diff --git a/spec/bundler/commands/remove_spec.rb b/spec/bundler/commands/remove_spec.rb index ceba6c5edebc47..093130f7d5f805 100644 --- a/spec/bundler/commands/remove_spec.rb +++ b/spec/bundler/commands/remove_spec.rb @@ -86,7 +86,7 @@ gem 'git' gem 'rack', git: "#{lib_path("rack-1.0")}", - branch: 'master' + branch: 'main' gem 'nokogiri' G diff --git a/spec/bundler/commands/show_spec.rb b/spec/bundler/commands/show_spec.rb index 2adb121616639e..925e40b71b2b24 100644 --- a/spec/bundler/commands/show_spec.rb +++ b/spec/bundler/commands/show_spec.rb @@ -100,10 +100,10 @@ expect(the_bundle).to include_gems "foo 1.0" bundle :show - expect(out).to include("foo (1.0 #{@git.ref_for("master", 6)}") + expect(out).to include("foo (1.0 #{@git.ref_for("main", 6)}") end - it "prints out branch names other than master" do + it "prints out branch names other than main" do update_git "foo", :branch => "omg" do |s| s.write "lib/foo.rb", "FOO = '1.0.omg'" end diff --git a/spec/bundler/commands/update_spec.rb b/spec/bundler/commands/update_spec.rb index d45a5654753476..8ca537ac10da74 100644 --- a/spec/bundler/commands/update_spec.rb +++ b/spec/bundler/commands/update_spec.rb @@ -983,7 +983,7 @@ context "when the Gemfile removes the ruby" do before do install_gemfile <<-G - ruby '~> #{RUBY_VERSION}' + ruby '~> #{Gem.ruby_version}' source "#{file_uri_for(gem_repo1)}" G @@ -1013,12 +1013,12 @@ context "when the Gemfile specified an updated Ruby version" do before do install_gemfile <<-G - ruby '~> #{RUBY_VERSION}' + ruby '~> #{Gem.ruby_version}' source "#{file_uri_for(gem_repo1)}" G gemfile <<-G - ruby '~> #{RUBY_VERSION[0..2]}' + ruby '~> #{current_ruby_minor}' source "#{file_uri_for(gem_repo1)}" G end @@ -1047,7 +1047,7 @@ context "when a different Ruby is being used than has been versioned" do before do install_gemfile <<-G - ruby '~> #{RUBY_VERSION}' + ruby '~> #{Gem.ruby_version}' source "#{file_uri_for(gem_repo1)}" G @@ -1083,7 +1083,7 @@ L gemfile <<-G - ruby '~> #{RUBY_VERSION}' + ruby '~> #{Gem.ruby_version}' source "#{file_uri_for(gem_repo1)}" G end diff --git a/spec/bundler/install/gemfile/git_spec.rb b/spec/bundler/install/gemfile/git_spec.rb index 3f8a5afc4070ec..20586741059138 100644 --- a/spec/bundler/install/gemfile/git_spec.rb +++ b/spec/bundler/install/gemfile/git_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true RSpec.describe "bundle install with git sources" do - describe "when floating on master" do + describe "when floating on main" do before :each do build_git "foo" do |s| s.executables = "foobar" @@ -51,7 +51,7 @@ bundle "update foo" - sha = git.ref_for("master", 11) + sha = git.ref_for("main", 11) spec_file = default_bundle_path.join("bundler/gems/foo-1.0-#{sha}/foo.gemspec").to_s ruby_code = Gem::Specification.load(spec_file).to_ruby file_code = File.read(spec_file) @@ -219,12 +219,12 @@ end it "works when the revision is a non-head ref" do - # want to ensure we don't fallback to master + # want to ensure we don't fallback to main update_git "foo", :path => lib_path("foo-1.0") do |s| s.write("lib/foo.rb", "raise 'FAIL'") end - sys_exec("git update-ref -m \"Bundler Spec!\" refs/bundler/1 master~1", :dir => lib_path("foo-1.0")) + sys_exec("git update-ref -m \"Bundler Spec!\" refs/bundler/1 main~1", :dir => lib_path("foo-1.0")) # want to ensure we don't fallback to HEAD update_git "foo", :path => lib_path("foo-1.0"), :branch => "rando" do |s| @@ -255,12 +255,12 @@ end G - # want to ensure we don't fallback to master + # want to ensure we don't fallback to main update_git "foo", :path => lib_path("foo-1.0") do |s| s.write("lib/foo.rb", "raise 'FAIL'") end - sys_exec("git update-ref -m \"Bundler Spec!\" refs/bundler/1 master~1", :dir => lib_path("foo-1.0")) + sys_exec("git update-ref -m \"Bundler Spec!\" refs/bundler/1 main~1", :dir => lib_path("foo-1.0")) # want to ensure we don't fallback to HEAD update_git "foo", :path => lib_path("foo-1.0"), :branch => "rando" do |s| @@ -284,7 +284,7 @@ end it "does not download random non-head refs" do - sys_exec("git update-ref -m \"Bundler Spec!\" refs/bundler/1 master~1", :dir => lib_path("foo-1.0")) + sys_exec("git update-ref -m \"Bundler Spec!\" refs/bundler/1 main~1", :dir => lib_path("foo-1.0")) bundle "config set global_gem_cache true" @@ -420,7 +420,7 @@ gemfile <<-G source "#{file_uri_for(gem_repo1)}" - gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master" + gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main" G bundle %(config set local.rack #{lib_path("local-rack")}) @@ -441,7 +441,7 @@ install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" - gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master" + gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main" G bundle %(config set local.rack #{lib_path("local-rack")}) @@ -461,7 +461,7 @@ install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" - gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master" + gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main" G bundle %(config set local.rack #{lib_path("local-rack")}) @@ -477,7 +477,7 @@ install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" - gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master" + gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main" G lockfile0 = File.read(bundled_app_lock) @@ -499,7 +499,7 @@ install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" - gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master" + gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main" G lockfile0 = File.read(bundled_app_lock) @@ -519,7 +519,7 @@ install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" - gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master" + gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main" G bundle %(config set local.rack #{lib_path("local-rack")}) @@ -583,12 +583,12 @@ install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" - gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master" + gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main" G bundle %(config set local.rack #{lib_path("local-rack")}) bundle :install, :raise_on_error => false - expect(err).to match(/is using branch another but Gemfile specifies master/) + expect(err).to match(/is using branch another but Gemfile specifies main/) end it "explodes on invalid revision on install" do @@ -600,7 +600,7 @@ install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" - gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master" + gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main" G bundle %(config set local.rack #{lib_path("local-rack")}) @@ -617,7 +617,7 @@ install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" - gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master" + gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main" G bundle %(config set local.rack #{lib_path("local-rack")}) @@ -1519,7 +1519,7 @@ gemfile <<-G source "#{file_uri_for(gem_repo1)}" - gem "foo", :git => "#{lib_path("foo")}", :branch => "master" + gem "foo", :git => "#{lib_path("foo")}", :branch => "main" G bundle :install diff --git a/spec/bundler/install/gemfile/ruby_spec.rb b/spec/bundler/install/gemfile/ruby_spec.rb index ba250acfddf4a4..39f09031b7abca 100644 --- a/spec/bundler/install/gemfile/ruby_spec.rb +++ b/spec/bundler/install/gemfile/ruby_spec.rb @@ -11,13 +11,13 @@ def locked_ruby_version it "allows adding gems" do install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" - ruby "#{RUBY_VERSION}" + ruby "#{Gem.ruby_version}" gem "rack" G install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" - ruby "#{RUBY_VERSION}" + ruby "#{Gem.ruby_version}" gem "rack" gem "rack-obama" G @@ -28,7 +28,7 @@ def locked_ruby_version it "allows removing the ruby version requirement" do install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" - ruby "~> #{RUBY_VERSION}" + ruby "~> #{Gem.ruby_version}" gem "rack" G @@ -46,7 +46,7 @@ def locked_ruby_version it "allows changing the ruby version requirement to something compatible" do install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" - ruby ">= #{RUBY_VERSION[0..2]}.0" + ruby ">= #{current_ruby_minor}" gem "rack" G @@ -55,7 +55,7 @@ def locked_ruby_version install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" - ruby ">= #{RUBY_VERSION}" + ruby ">= #{Gem.ruby_version}" gem "rack" G @@ -93,7 +93,7 @@ def locked_ruby_version install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" - ruby ">= #{RUBY_VERSION[0..2]}.0" + ruby ">= #{current_ruby_minor}" gem "rack" G @@ -104,7 +104,7 @@ def locked_ruby_version it "allows requirements with trailing whitespace" do install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" - ruby "#{RUBY_VERSION}\\n \t\\n" + ruby "#{Gem.ruby_version}\\n \t\\n" gem "rack" G diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb index 89c812e5d5a553..ee0aa2a34761af 100644 --- a/spec/bundler/install/gemfile/sources_spec.rb +++ b/spec/bundler/install/gemfile/sources_spec.rb @@ -1563,4 +1563,43 @@ L end end + + context "when mistakenly adding a top level gem already depended on and cached under the wrong source" do + before do + build_repo4 do + build_gem "some_private_gem", "0.1.0" do |s| + s.add_dependency "example", "~> 1.0" + end + end + + build_repo2 do + build_gem "example", "1.0.0" + end + + install_gemfile <<~G, :artifice => "compact_index" + source "https://gem.repo2" + + source "https://gem.repo4" do + gem "some_private_gem" + end + G + + gemfile <<~G + source "https://gem.repo2" + + source "https://gem.repo4" do + gem "some_private_gem" + gem "example" # MISTAKE, example is not available at gem.repo4 + end + G + end + + it "shows a proper error message and does not generate a corrupted lockfile" do + expect do + bundle :install, :artifice => "compact_index", :raise_on_error => false, :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } + end.not_to change { lockfile } + + expect(err).to include("Could not find gem 'example' in rubygems repository https://gem.repo4/") + end + end end diff --git a/spec/bundler/install/gemfile/specific_platform_spec.rb b/spec/bundler/install/gemfile/specific_platform_spec.rb index 276a84f2a6b6cc..48349aaef4353a 100644 --- a/spec/bundler/install/gemfile/specific_platform_spec.rb +++ b/spec/bundler/install/gemfile/specific_platform_spec.rb @@ -180,7 +180,7 @@ lockfile <<-L GIT remote: #{lib_path("pg_array_parser-1.0")} - revision: #{git.ref_for("master")} + revision: #{git.ref_for("main")} specs: pg_array_parser (1.0-java) pg_array_parser (1.0) @@ -374,6 +374,41 @@ ERROR end + it "can fallback to a source gem when platform gems are incompatible with current ruby version" do + setup_multiplatform_gem_with_source_gem + + source = file_uri_for(gem_repo2) + + gemfile <<~G + source "#{source}" + + gem "my-precompiled-gem" + G + + # simulate lockfile which includes both a precompiled gem with: + # - Gem the current platform (with imcompatible ruby version) + # - A source gem with compatible ruby version + lockfile <<-L + GEM + remote: #{source}/ + specs: + my-precompiled-gem (3.0.0) + my-precompiled-gem (3.0.0-#{Bundler.local_platform}) + + PLATFORMS + ruby + #{Bundler.local_platform} + + DEPENDENCIES + my-precompiled-gem + + BUNDLED WITH + #{Bundler::VERSION} + L + + bundle :install + end + private def setup_multiplatform_gem @@ -404,4 +439,16 @@ def setup_multiplatform_gem_with_different_dependencies_per_platform build_gem("CFPropertyList") end end + + def setup_multiplatform_gem_with_source_gem + build_repo2 do + build_gem("my-precompiled-gem", "3.0.0") + build_gem("my-precompiled-gem", "3.0.0") do |s| + s.platform = Bundler.local_platform + + # purposely unresolvable + s.required_ruby_version = ">= 1000.0.0" + end + end + end end diff --git a/spec/bundler/install/gems/fund_spec.rb b/spec/bundler/install/gems/fund_spec.rb index f521b0296f31e4..436454c1f404e8 100644 --- a/spec/bundler/install/gems/fund_spec.rb +++ b/spec/bundler/install/gems/fund_spec.rb @@ -52,6 +52,33 @@ end end + context "when gems include a fund URI but `ignore_funding_requests` is configured" do + before do + bundle "config set ignore_funding_requests true" + end + + it "does not display the plural fund message after installing" do + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem 'has_funding_and_other_metadata' + gem 'has_funding' + gem 'rack-obama' + G + + expect(out).not_to include("2 installed gems you directly depend on are looking for funding.") + end + + it "does not display the singular fund message after installing" do + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + gem 'has_funding' + gem 'rack-obama' + G + + expect(out).not_to include("1 installed gem you directly depend on is looking for funding.") + end + end + context "when gems do not include fund messages" do it "does not display any fund messages" do install_gemfile <<-G diff --git a/spec/bundler/install/gems/resolving_spec.rb b/spec/bundler/install/gems/resolving_spec.rb index b136dea8bd3329..9c0d6bfe56cba7 100644 --- a/spec/bundler/install/gems/resolving_spec.rb +++ b/spec/bundler/install/gems/resolving_spec.rb @@ -211,12 +211,12 @@ end install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } - ruby "#{RUBY_VERSION}" + ruby "#{Gem.ruby_version}" source "http://localgemserver.test/" gem 'rack' G - expect(out).to_not include("rack-9001.0.0 requires ruby version > 9000") + expect(err).to_not include("rack-9001.0.0 requires ruby version > 9000") expect(the_bundle).to include_gems("rack 1.2") end @@ -232,50 +232,77 @@ end install_gemfile <<-G, :artifice => "endpoint", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } - ruby "#{RUBY_VERSION}" + ruby "#{Gem.ruby_version}" source "http://localgemserver.test/" gem 'rack' G - expect(out).to_not include("rack-9001.0.0 requires ruby version > 9000") + expect(err).to_not include("rack-9001.0.0 requires ruby version > 9000") expect(the_bundle).to include_gems("rack 1.2") end - it "gives a meaningful error if there's a lockfile using the newer incompatible version" do - build_repo2 do - build_gem "parallel_tests", "3.7.0" do |s| - s.required_ruby_version = ">= #{current_ruby_minor}" - end + context "when there is a lockfile using the newer incompatible version" do + before do + build_repo2 do + build_gem "parallel_tests", "3.7.0" do |s| + s.required_ruby_version = ">= #{current_ruby_minor}" + end - build_gem "parallel_tests", "3.8.0" do |s| - s.required_ruby_version = ">= #{next_ruby_minor}" + build_gem "parallel_tests", "3.8.0" do |s| + s.required_ruby_version = ">= #{next_ruby_minor}" + end end + + gemfile <<-G + source "http://localgemserver.test/" + gem 'parallel_tests' + G + + lockfile <<~L + GEM + remote: http://localgemserver.test/ + specs: + parallel_tests (3.8.0) + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + parallel_tests + + BUNDLED WITH + #{Bundler::VERSION} + L end - gemfile <<-G - source "http://localgemserver.test/" - gem 'parallel_tests' - G + it "automatically updates lockfile to use the older version" do + bundle "install --verbose", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s } + + expect(lockfile).to eq <<~L + GEM + remote: http://localgemserver.test/ + specs: + parallel_tests (3.7.0) - lockfile <<~L - GEM - remote: http://localgemserver.test/ - specs: - parallel_tests (3.8.0) + PLATFORMS + #{lockfile_platforms} - PLATFORMS - #{lockfile_platforms} + DEPENDENCIES + parallel_tests - DEPENDENCIES - parallel_tests + BUNDLED WITH + #{Bundler::VERSION} + L + end - BUNDLED WITH - #{Bundler::VERSION} - L + it "gives a meaningful error if we're in frozen mode" do + expect do + bundle "install --verbose", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s, "BUNDLE_FROZEN" => "true" }, :raise_on_error => false + end.not_to change { lockfile } - bundle "install --verbose", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }, :raise_on_error => false - expect(err).to include("parallel_tests-3.8.0 requires ruby version >= #{next_ruby_minor}") - expect(err).not_to include("That means the author of parallel_tests (3.8.0) has removed it.") + expect(err).to include("parallel_tests-3.8.0 requires ruby version >= #{next_ruby_minor}") + expect(err).not_to include("That means the author of parallel_tests (3.8.0) has removed it.") + end end it "gives a meaningful error on ruby version mismatches between dependencies" do @@ -309,13 +336,13 @@ end install_gemfile <<-G, :artifice => "compact_index_rate_limited", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } - ruby "#{RUBY_VERSION}" + ruby "#{Gem.ruby_version}" source "http://localgemserver.test/" gem 'rack' gem 'foo1' G - expect(out).to_not include("rack-9001.0.0 requires ruby version > 9000") + expect(err).to_not include("rack-9001.0.0 requires ruby version > 9000") expect(the_bundle).to include_gems("rack 1.2") end @@ -333,14 +360,14 @@ simulate_platform mingw do install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s } - ruby "#{RUBY_VERSION}" + ruby "#{Gem.ruby_version}" source "http://localgemserver.test/" gem 'rack' G end - expect(out).to_not include("rack-9001.0.0 requires ruby version > 9000") - expect(out).to_not include("rack-1.2-#{Bundler.local_platform} requires ruby version > 9000") + expect(err).to_not include("rack-9001.0.0 requires ruby version > 9000") + expect(err).to_not include("rack-1.2-#{Bundler.local_platform} requires ruby version > 9000") expect(the_bundle).to include_gems("rack 1.2") end end @@ -354,8 +381,8 @@ end end - let(:ruby_requirement) { %("#{RUBY_VERSION}") } - let(:error_message_requirement) { "= #{RUBY_VERSION}" } + let(:ruby_requirement) { %("#{Gem.ruby_version}") } + let(:error_message_requirement) { "= #{Gem.ruby_version}" } it "raises a proper error that mentions the current Ruby version during resolution" do install_gemfile <<-G, :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo2.to_s }, :raise_on_error => false diff --git a/spec/bundler/install/gems/standalone_spec.rb b/spec/bundler/install/gems/standalone_spec.rb index a5302877c1f4f2..238006c02bebba 100644 --- a/spec/bundler/install/gems/standalone_spec.rb +++ b/spec/bundler/install/gems/standalone_spec.rb @@ -461,3 +461,31 @@ include_examples("bundle install --standalone") end + +RSpec.describe "bundle install --standalone --local" do + before do + gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + gem "rack" + G + + system_gems "rack-1.0.0", :path => default_bundle_path + end + + it "generates script pointing to system gems" do + bundle "install --standalone --local --verbose" + + expect(out).to include("Using rack 1.0.0") + + load_error_ruby <<-RUBY, "spec" + require "./bundler/setup" + + require "rack" + puts RACK + require "spec" + RUBY + + expect(out).to eq("1.0.0") + expect(err).to eq("ZOMG LOAD ERROR") + end +end diff --git a/spec/bundler/install/gemspecs_spec.rb b/spec/bundler/install/gemspecs_spec.rb index 3684d8749df09b..7b58ea98391504 100644 --- a/spec/bundler/install/gemspecs_spec.rb +++ b/spec/bundler/install/gemspecs_spec.rb @@ -94,7 +94,8 @@ module Persistent💎 end context "when ruby version is specified in gemspec and gemfile" do - it "installs when patch level is not specified and the version matches" do + it "installs when patch level is not specified and the version matches", + :if => RUBY_PATCHLEVEL >= 0 do build_lib("foo", :path => bundled_app) do |s| s.required_ruby_version = "~> #{RUBY_VERSION}.0" end diff --git a/spec/bundler/install/git_spec.rb b/spec/bundler/install/git_spec.rb index d43aacee7e92b5..0fa7ed85317947 100644 --- a/spec/bundler/install/git_spec.rb +++ b/spec/bundler/install/git_spec.rb @@ -10,7 +10,7 @@ gem "foo", :git => "#{file_uri_for(lib_path("foo"))}" G - expect(out).to include("Using foo 1.0 from #{file_uri_for(lib_path("foo"))} (at master@#{revision_for(lib_path("foo"))[0..6]})") + expect(out).to include("Using foo 1.0 from #{file_uri_for(lib_path("foo"))} (at main@#{revision_for(lib_path("foo"))[0..6]})") expect(the_bundle).to include_gems "foo 1.0", :source => "git@#{lib_path("foo")}" end @@ -37,16 +37,16 @@ install_gemfile <<-G, :verbose => true source "#{file_uri_for(gem_repo1)}" - gem "foo", :git => "#{file_uri_for(lib_path("foo"))}", :ref => "master~2" + gem "foo", :git => "#{file_uri_for(lib_path("foo"))}", :ref => "main~2" G - expect(out).to include("Using foo 1.0 from #{file_uri_for(lib_path("foo"))} (at master~2@#{rev})") + expect(out).to include("Using foo 1.0 from #{file_uri_for(lib_path("foo"))} (at main~2@#{rev})") expect(the_bundle).to include_gems "foo 1.0", :source => "git@#{lib_path("foo")}" update_git "foo", "4.0", :path => lib_path("foo"), :gemspec => true bundle :update, :all => true, :verbose => true - expect(out).to include("Using foo 2.0 (was 1.0) from #{file_uri_for(lib_path("foo"))} (at master~2@#{rev2})") + expect(out).to include("Using foo 2.0 (was 1.0) from #{file_uri_for(lib_path("foo"))} (at main~2@#{rev2})") expect(the_bundle).to include_gems "foo 2.0", :source => "git@#{lib_path("foo")}" end diff --git a/spec/bundler/install/yanked_spec.rb b/spec/bundler/install/yanked_spec.rb index 3acae85afdd771..44fbb0bda3a5f1 100644 --- a/spec/bundler/install/yanked_spec.rb +++ b/spec/bundler/install/yanked_spec.rb @@ -15,7 +15,7 @@ foo (10.0.0) PLATFORMS - ruby + #{lockfile_platforms} DEPENDENCIES foo (= 10.0.0) @@ -57,7 +57,7 @@ rack (0.9.1) PLATFORMS - ruby + #{lockfile_platforms} DEPENDENCIES rack (= 0.9.1) @@ -86,7 +86,7 @@ rack_middleware (1.0) PLATFORMS - ruby + #{lockfile_platforms} DEPENDENCIES rack (= 0.9.1) diff --git a/spec/bundler/lock/lockfile_spec.rb b/spec/bundler/lock/lockfile_spec.rb index ea9893fb0e5bd7..29f8863591b44f 100644 --- a/spec/bundler/lock/lockfile_spec.rb +++ b/spec/bundler/lock/lockfile_spec.rb @@ -386,7 +386,7 @@ expect(lockfile).to eq <<~G GIT remote: #{lib_path("foo-1.0")} - revision: #{git.ref_for("master")} + revision: #{git.ref_for("main")} specs: foo (1.0) @@ -457,7 +457,7 @@ expect(lockfile).to eq <<~G GIT remote: #{lib_path("foo-1.0")} - revision: #{git.ref_for("master")} + revision: #{git.ref_for("main")} specs: foo (1.0) @@ -617,7 +617,7 @@ expect(lockfile).to eq <<~G GIT remote: #{lib_path("bar-1.0")} - revision: #{bar.ref_for("master")} + revision: #{bar.ref_for("main")} specs: bar (1.0) @@ -1174,7 +1174,7 @@ it "captures the Ruby version in the lockfile" do install_gemfile <<-G source "#{file_uri_for(gem_repo2)}/" - ruby '#{RUBY_VERSION}' + ruby '#{Gem.ruby_version}' gem "rack", "> 0.9", "< 1.0" G @@ -1191,7 +1191,7 @@ rack (> 0.9, < 1.0) RUBY VERSION - ruby #{RUBY_VERSION}p#{RUBY_PATCHLEVEL} + #{Bundler::RubyVersion.system} BUNDLED WITH #{Bundler::VERSION} diff --git a/spec/bundler/plugins/source/example_spec.rb b/spec/bundler/plugins/source/example_spec.rb index 7d098997ec0496..412de04d441e2f 100644 --- a/spec/bundler/plugins/source/example_spec.rb +++ b/spec/bundler/plugins/source/example_spec.rb @@ -203,7 +203,7 @@ class SPlugin < Bundler::Plugin::API def initialize(opts) super - @ref = options["ref"] || options["branch"] || options["tag"] || "master" + @ref = options["ref"] || options["branch"] || options["tag"] || "main" @unlocked = false end @@ -247,7 +247,7 @@ def install(spec, opts) def options_to_lock opts = {"revision" => revision} - opts["ref"] = ref if ref != "master" + opts["ref"] = ref if ref != "main" opts end @@ -435,7 +435,7 @@ def installed? describe "bundle cache with gitp" do it "copies repository to vendor cache and uses it" do git = build_git "foo" - ref = git.ref_for("master", 11) + ref = git.ref_for("main", 11) install_gemfile <<-G source "#{file_uri_for(gem_repo2)}" # plugin source diff --git a/spec/bundler/quality_spec.rb b/spec/bundler/quality_spec.rb index 62f3722a392967..ee98bcd4d7c82e 100644 --- a/spec/bundler/quality_spec.rb +++ b/spec/bundler/quality_spec.rb @@ -22,7 +22,7 @@ def check_for_git_merge_conflicts(filename) def check_for_tab_characters(filename) failing_lines = [] each_line(filename) do |line, number| - failing_lines << number + 1 if line =~ /\t/ + failing_lines << number + 1 if line.include?("\t") end return if failing_lines.empty? diff --git a/spec/bundler/realworld/edgecases_spec.rb b/spec/bundler/realworld/edgecases_spec.rb index 30c922efb0771d..2a667011a10fec 100644 --- a/spec/bundler/realworld/edgecases_spec.rb +++ b/spec/bundler/realworld/edgecases_spec.rb @@ -218,7 +218,7 @@ def rubygems_version(name, requirement) end it "doesn't hang on big gemfile" do - skip "Only for ruby 2.7.3" if RUBY_VERSION != "2.7.3" || RUBY_PLATFORM =~ /darwin/ + skip "Only for ruby 2.7.3" if RUBY_VERSION != "2.7.3" || RUBY_PLATFORM.include?("darwin") gemfile <<~G # frozen_string_literal: true @@ -330,7 +330,7 @@ def rubygems_version(name, requirement) end it "doesn't hang on tricky gemfile" do - skip "Only for ruby 2.7.3" if RUBY_VERSION != "2.7.3" || RUBY_PLATFORM =~ /darwin/ + skip "Only for ruby 2.7.3" if RUBY_VERSION != "2.7.3" || RUBY_PLATFORM.include?("darwin") gemfile <<~G source 'https://rubygems.org' @@ -356,7 +356,7 @@ def rubygems_version(name, requirement) end it "doesn't hang on nix gemfile" do - skip "Only for ruby 3.0.1" if RUBY_VERSION != "3.0.1" || RUBY_PLATFORM =~ /darwin/ + skip "Only for ruby 3.0.1" if RUBY_VERSION != "3.0.1" || RUBY_PLATFORM.include?("darwin") gemfile <<~G source "https://rubygems.org" do diff --git a/spec/bundler/resolver/basic_spec.rb b/spec/bundler/resolver/basic_spec.rb index ee62dc3577aba8..7182d1e29c6ffc 100644 --- a/spec/bundler/resolver/basic_spec.rb +++ b/spec/bundler/resolver/basic_spec.rb @@ -233,7 +233,7 @@ it "resolves foo only to latest patch - changing dependency declared case" do # bar is locked AND a declared dependency in the Gemfile, so it will not move, and therefore # foo can only move up to 1.4.4. - @base << build_spec("bar", "2.0.3").first + @base << Bundler::LazySpecification.new("bar", "2.0.3", nil) should_conservative_resolve_and_include :patch, ["foo"], %w[foo-1.4.4 bar-2.0.3] end diff --git a/spec/bundler/runtime/platform_spec.rb b/spec/bundler/runtime/platform_spec.rb index 34dc5ba7990241..a7161c9cfea263 100644 --- a/spec/bundler/runtime/platform_spec.rb +++ b/spec/bundler/runtime/platform_spec.rb @@ -281,30 +281,59 @@ expect(the_bundle).to include_gems "platform_specific 1.0 RUBY" - build_repo4 do - build_gem "libv8" + simulate_platform "x86_64-linux" do + build_repo4 do + build_gem "libv8" - build_gem "libv8" do |s| - s.platform = Bundler.local_platform + build_gem "libv8" do |s| + s.platform = "x86_64-linux" + end end + + gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + gem "libv8" + G + + lockfile <<-L + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + libv8 (1.0) + + PLATFORMS + ruby + + DEPENDENCIES + libv8 + + BUNDLED WITH + #{Bundler::VERSION} + L + + bundle "install" + + expect(the_bundle).to include_gems "libv8 1.0 x86_64-linux" end + end + it "doesn't pull platform specific gems on truffleruby, even if lockfile only includes those", :truffleruby_only do gemfile <<-G - source "#{file_uri_for(gem_repo4)}" - gem "libv8" + source "#{file_uri_for(gem_repo1)}" + gem "platform_specific" G lockfile <<-L GEM - remote: #{file_uri_for(gem_repo4)}/ + remote: #{file_uri_for(gem_repo1)}/ specs: - libv8 (1.0) + platform_specific (1.0-x86-darwin-100) PLATFORMS - ruby + x86-darwin-100 DEPENDENCIES - libv8 + platform_specific BUNDLED WITH #{Bundler::VERSION} @@ -312,7 +341,7 @@ bundle "install" - expect(the_bundle).to include_gems "libv8 1.0 #{Bundler.local_platform}" + expect(the_bundle).to include_gems "platform_specific 1.0 RUBY" end it "allows specifying only-ruby-platform on windows with dependency platforms" do @@ -379,6 +408,7 @@ gem "requires_platform_specific" G + expect(out).to include("lockfile does not have all gems needed for the current platform") expect(the_bundle).to include_gem "platform_specific 1.0 x64-mingw32" end end diff --git a/spec/bundler/runtime/setup_spec.rb b/spec/bundler/runtime/setup_spec.rb index fecf4cd98bb3c6..29445b420ce11d 100644 --- a/spec/bundler/runtime/setup_spec.rb +++ b/spec/bundler/runtime/setup_spec.rb @@ -370,7 +370,7 @@ def clean_load_path(lp) context "when the ruby stdlib is a substring of Gem.path" do it "does not reject the stdlib from $LOAD_PATH" do - substring = "/" + $LOAD_PATH.find {|p| p =~ /vendor_ruby/ }.split("/")[2] + substring = "/" + $LOAD_PATH.find {|p| p.include?("vendor_ruby") }.split("/")[2] run "puts 'worked!'", :env => { "GEM_PATH" => substring } expect(out).to eq("worked!") end @@ -489,7 +489,7 @@ def clean_load_path(lp) gemfile <<-G source "#{file_uri_for(gem_repo1)}" - gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master" + gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main" G bundle %(config set local.rack #{lib_path("local-rack")}) @@ -507,7 +507,7 @@ def clean_load_path(lp) gemfile <<-G source "#{file_uri_for(gem_repo1)}" - gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master" + gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main" G bundle %(config set local.rack #{lib_path("local-rack")}) @@ -529,7 +529,7 @@ def clean_load_path(lp) gemfile <<-G source "#{file_uri_for(gem_repo1)}" - gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "master" + gem "rack", :git => "#{lib_path("rack-0.8")}", :branch => "main" G bundle %(config set local.rack #{lib_path("local-rack")}) @@ -541,7 +541,7 @@ def clean_load_path(lp) G run "require 'rack'", :raise_on_error => false - expect(err).to match(/is using branch master but Gemfile specifies changed/) + expect(err).to match(/is using branch main but Gemfile specifies changed/) end it "explodes on refs with different branches on runtime" do @@ -551,17 +551,17 @@ def clean_load_path(lp) install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" - gem "rack", :git => "#{lib_path("rack-0.8")}", :ref => "master", :branch => "master" + gem "rack", :git => "#{lib_path("rack-0.8")}", :ref => "main", :branch => "main" G gemfile <<-G source "#{file_uri_for(gem_repo1)}" - gem "rack", :git => "#{lib_path("rack-0.8")}", :ref => "master", :branch => "nonexistant" + gem "rack", :git => "#{lib_path("rack-0.8")}", :ref => "main", :branch => "nonexistant" G bundle %(config set local.rack #{lib_path("local-rack")}) run "require 'rack'", :raise_on_error => false - expect(err).to match(/is using branch master but Gemfile specifies nonexistant/) + expect(err).to match(/is using branch main but Gemfile specifies nonexistant/) end end @@ -634,6 +634,7 @@ def clean_load_path(lp) ruby "require '#{system_gem_path("gems/bundler-9.99.9.beta1/lib/bundler.rb")}'; Bundler.setup", :env => { "DEBUG" => "1" } expect(out).to include("Found no changes, using resolution from the lockfile") + expect(out).not_to include("lockfile does not have all gems needed for the current platform") expect(err).to be_empty end @@ -864,7 +865,7 @@ def clean_load_path(lp) gemspec_content = File.binread(gemspec). sub("Bundler::VERSION", %("#{Bundler::VERSION}")). - lines.reject {|line| line =~ %r{lib/bundler/version} }.join + lines.reject {|line| line.include?("lib/bundler/version") }.join File.open(File.join(specifications_dir, "#{full_name}.gemspec"), "wb") do |f| f.write(gemspec_content) diff --git a/spec/bundler/support/builders.rb b/spec/bundler/support/builders.rb index 285b68c047ac65..a4d4c9f085366b 100644 --- a/spec/bundler/support/builders.rb +++ b/spec/bundler/support/builders.rb @@ -94,8 +94,8 @@ def build_repo1 end build_gem "platform_specific" do |s| - s.platform = Bundler.local_platform - s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 #{Bundler.local_platform}'" + s.platform = Gem::Platform.local + s.write "lib/platform_specific.rb", "PLATFORM_SPECIFIC = '1.0.0 #{Gem::Platform.local}'" end build_gem "platform_specific" do |s| @@ -528,7 +528,7 @@ def platform_string class GitBuilder < LibBuilder def _build(options) - default_branch = options[:default_branch] || "master" + default_branch = options[:default_branch] || "main" path = options[:path] || _default_path source = options[:source] || "git@#{path}" super(options.merge(:path => path, :source => source)) diff --git a/spec/bundler/support/helpers.rb b/spec/bundler/support/helpers.rb index 03c0df3b508884..af6e33885348fe 100644 --- a/spec/bundler/support/helpers.rb +++ b/spec/bundler/support/helpers.rb @@ -476,7 +476,7 @@ def env_for_missing_prerelease_default_gem_activation end def current_ruby_minor - Gem.ruby_version.segments[0..1].join(".") + Gem.ruby_version.segments.tap {|s| s.delete_at(2) }.join(".") end def next_ruby_minor diff --git a/spec/bundler/support/indexes.rb b/spec/bundler/support/indexes.rb index 638f394e76a70b..55d798a90a11ff 100644 --- a/spec/bundler/support/indexes.rb +++ b/spec/bundler/support/indexes.rb @@ -26,6 +26,7 @@ def resolve(args = []) end end args[0] ||= [] # base + args[0].each {|ls| ls.source = default_source } args[1] ||= Bundler::GemVersionPromoter.new # gem_version_promoter args[2] ||= [] # additional_base_requirements args[3] ||= @platforms # platforms diff --git a/spec/bundler/support/platforms.rb b/spec/bundler/support/platforms.rb index 48479723e47f13..1ad7778403f350 100644 --- a/spec/bundler/support/platforms.rb +++ b/spec/bundler/support/platforms.rb @@ -71,7 +71,7 @@ def local_ruby_engine end def local_engine_version - RUBY_ENGINE_VERSION + RUBY_ENGINE == "ruby" ? Gem.ruby_version : RUBY_ENGINE_VERSION end def not_local_engine_version diff --git a/spec/bundler/update/git_spec.rb b/spec/bundler/update/git_spec.rb index 0787ee41a73f78..da92cab1cc14f3 100644 --- a/spec/bundler/update/git_spec.rb +++ b/spec/bundler/update/git_spec.rb @@ -57,7 +57,7 @@ expect(the_bundle).to include_gems "foo 1.1" end - it "floats on master when updating all gems that are pinned to the source even if you have child dependencies" do + it "floats on main when updating all gems that are pinned to the source even if you have child dependencies" do build_git "foo", :path => lib_path("foo") build_gem "bar", :to_bundle => true do |s| s.add_dependency "foo" @@ -103,7 +103,7 @@ build_git "foo" @remote = build_git("bar", :bare => true) update_git "foo", :remote => file_uri_for(@remote.path) - update_git "foo", :push => "master" + update_git "foo", :push => "main" install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" @@ -211,7 +211,7 @@ install_gemfile <<-G source "#{file_uri_for(gem_repo1)}" - gem "rack", :git => "#{file_uri_for(lib_path("rack-0.8"))}", :branch => "master" + gem "rack", :git => "#{file_uri_for(lib_path("rack-0.8"))}", :branch => "main" G bundle %(config set local.rack #{lib_path("local-rack")}) @@ -230,7 +230,7 @@ update_git "rails", "3.0", :path => lib_path("rails"), :gemspec => true bundle "update", :all => true - expect(out).to include("Using rails 3.0 (was 2.3.2) from #{file_uri_for(lib_path("rails"))} (at master@#{revision_for(lib_path("rails"))[0..6]})") + expect(out).to include("Using rails 3.0 (was 2.3.2) from #{file_uri_for(lib_path("rails"))} (at main@#{revision_for(lib_path("rails"))[0..6]})") end end @@ -301,7 +301,7 @@ s.write "foo.gemspec", spec_lines.join("\n") end - ref = @git.ref_for "master" + ref = @git.ref_for "main" bundle "update --source bar" diff --git a/spec/mspec/lib/mspec/guards/superuser.rb b/spec/mspec/lib/mspec/guards/superuser.rb index e92ea7e8628945..24daf9b26cd2e5 100644 --- a/spec/mspec/lib/mspec/guards/superuser.rb +++ b/spec/mspec/lib/mspec/guards/superuser.rb @@ -6,10 +6,20 @@ def match? end end +class RealSuperUserGuard < SpecGuard + def match? + Process.uid == 0 + end +end + def as_superuser(&block) SuperUserGuard.new.run_if(:as_superuser, &block) end +def as_real_superuser(&block) + RealSuperUserGuard.new.run_if(:as_real_superuser, &block) +end + def as_user(&block) SuperUserGuard.new.run_unless(:as_user, &block) end diff --git a/spec/ruby/core/enumerable/compact_spec.rb b/spec/ruby/core/enumerable/compact_spec.rb new file mode 100644 index 00000000000000..86e95dce085e96 --- /dev/null +++ b/spec/ruby/core/enumerable/compact_spec.rb @@ -0,0 +1,11 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +ruby_version_is '3.1' do + describe "Enumerable#compact" do + it 'returns array without nil elements' do + arr = EnumerableSpecs::Numerous.new(nil, 1, 2, nil, true) + arr.compact.should == [1, 2, true] + end + end +end diff --git a/spec/ruby/core/enumerator/lazy/lazy_spec.rb b/spec/ruby/core/enumerator/lazy/lazy_spec.rb index cde9b310661495..683dfb81d76d7a 100644 --- a/spec/ruby/core/enumerator/lazy/lazy_spec.rb +++ b/spec/ruby/core/enumerator/lazy/lazy_spec.rb @@ -16,6 +16,10 @@ ] lazy_methods += [:chunk_while, :uniq] + ruby_version_is '3.1' do + lazy_methods += [:compact] + end + Enumerator::Lazy.instance_methods(false).should include(*lazy_methods) end end @@ -26,3 +30,13 @@ lazy.lazy.should equal(lazy) end end + +ruby_version_is '3.1' do + describe "Enumerator::Lazy#compact" do + it 'returns array without nil elements' do + arr = [1, nil, 3, false, 5].to_enum.lazy.compact + arr.should be_an_instance_of(Enumerator::Lazy) + arr.force.should == [1, 3, false, 5] + end + end +end diff --git a/spec/ruby/core/file/shared/fnmatch.rb b/spec/ruby/core/file/shared/fnmatch.rb index 00682bb64cec07..94f22144b06046 100644 --- a/spec/ruby/core/file/shared/fnmatch.rb +++ b/spec/ruby/core/file/shared/fnmatch.rb @@ -159,10 +159,10 @@ end it "does not match leading periods in filenames with wildcards by default" do - File.send(@method, '*', '.profile').should == false - File.send(@method, '*', 'home/.profile').should == true - File.send(@method, '*/*', 'home/.profile').should == true - File.send(@method, '*/*', 'dave/.profile', File::FNM_PATHNAME).should == false + File.should_not.send(@method, '*', '.profile') + File.should.send(@method, '*', 'home/.profile') + File.should.send(@method, '*/*', 'home/.profile') + File.should_not.send(@method, '*/*', 'dave/.profile', File::FNM_PATHNAME) end it "matches patterns with leading periods to dotfiles by default" do diff --git a/spec/ruby/core/range/clone_spec.rb b/spec/ruby/core/range/clone_spec.rb new file mode 100644 index 00000000000000..cf6ce74da09883 --- /dev/null +++ b/spec/ruby/core/range/clone_spec.rb @@ -0,0 +1,26 @@ +require_relative '../../spec_helper' + +describe "Range#clone" do + it "duplicates the range" do + original = (1..3) + copy = original.clone + copy.begin.should == 1 + copy.end.should == 3 + copy.should_not.exclude_end? + copy.should_not.equal? original + + original = ("a"..."z") + copy = original.clone + copy.begin.should == "a" + copy.end.should == "z" + copy.should.exclude_end? + copy.should_not.equal? original + end + + it "maintains the frozen state" do + (1..2).clone.frozen?.should == (1..2).frozen? + (1..).clone.frozen?.should == (1..).frozen? + Range.new(1, 2).clone.frozen?.should == Range.new(1, 2).frozen? + Class.new(Range).new(1, 2).clone.frozen?.should == Class.new(Range).new(1, 2).frozen? + end +end diff --git a/spec/ruby/core/range/dup_spec.rb b/spec/ruby/core/range/dup_spec.rb index 976d4fd1d0910b..fab3c3f1b26ce2 100644 --- a/spec/ruby/core/range/dup_spec.rb +++ b/spec/ruby/core/range/dup_spec.rb @@ -2,10 +2,12 @@ describe "Range#dup" do it "duplicates the range" do - copy = (1..3).dup + original = (1..3) + copy = original.dup copy.begin.should == 1 copy.end.should == 3 copy.should_not.exclude_end? + copy.should_not.equal?(original) copy = ("a"..."z").dup copy.begin.should == "a" diff --git a/spec/ruby/core/range/new_spec.rb b/spec/ruby/core/range/new_spec.rb index 85e99babffe9f0..40df914b830400 100644 --- a/spec/ruby/core/range/new_spec.rb +++ b/spec/ruby/core/range/new_spec.rb @@ -65,5 +65,15 @@ range_exclude.should_not == range_include end + + ruby_version_is "3.0" do + it "creates a frozen range if the class is Range.class" do + Range.new(1, 2).should.frozen? + end + + it "does not create a frozen range if the class is not Range.class" do + Class.new(Range).new(1, 2).should_not.frozen? + end + end end end diff --git a/spec/ruby/core/regexp/shared/quote.rb b/spec/ruby/core/regexp/shared/quote.rb index 33bdfd99793962..953310276692f9 100644 --- a/spec/ruby/core/regexp/shared/quote.rb +++ b/spec/ruby/core/regexp/shared/quote.rb @@ -17,6 +17,11 @@ Regexp.send(@method, str).should == '\+\[\]\(' end + it "works for broken strings" do + Regexp.send(@method, "a.\x85b.".force_encoding("US-ASCII")).should =="a\\.\x85b\\.".force_encoding("US-ASCII") + Regexp.send(@method, "a.\x80".force_encoding("UTF-8")).should == "a\\.\x80".force_encoding("UTF-8") + end + it "sets the encoding of the result to US-ASCII if there are only US-ASCII characters present in the input String" do str = "abc".force_encoding("euc-jp") Regexp.send(@method, str).encoding.should == Encoding::US_ASCII diff --git a/spec/ruby/core/regexp/source_spec.rb b/spec/ruby/core/regexp/source_spec.rb index 709fee49b3ad2c..5f253da9ea0590 100644 --- a/spec/ruby/core/regexp/source_spec.rb +++ b/spec/ruby/core/regexp/source_spec.rb @@ -9,8 +9,26 @@ /x(.)xz/.source.should == "x(.)xz" end - it "will remove escape characters" do - /foo\/bar/.source.should == "foo/bar" + it "keeps escape sequences as is" do + /\x20\+/.source.should == '\x20\+' + end + + describe "escaping" do + it "keeps escaping of metacharacter" do + /\$/.source.should == "\\$" + end + + it "keeps escaping of metacharacter used as a terminator" do + %r+\++.source.should == "\\+" + end + + it "removes escaping of non-metacharacter used as a terminator" do + %r@\@@.source.should == "@" + end + + it "keeps escaping of non-metacharacter not used as a terminator" do + /\@/.source.should == "\\@" + end end not_supported_on :opal do diff --git a/spec/ruby/core/string/capitalize_spec.rb b/spec/ruby/core/string/capitalize_spec.rb index 8afaefc0210783..751f4160a67f0f 100644 --- a/spec/ruby/core/string/capitalize_spec.rb +++ b/spec/ruby/core/string/capitalize_spec.rb @@ -10,6 +10,7 @@ "hello".capitalize.should == "Hello" "HELLO".capitalize.should == "Hello" "123ABC".capitalize.should == "123abc" + "abcdef"[1...-1].capitalize.should == "Bcde" end describe "full Unicode case mapping" do @@ -37,7 +38,7 @@ end it "handles non-ASCII substrings properly" do - "garçon"[1..-1].capitalize(:ascii).should == "Arçon" + "garçon"[1...-1].capitalize(:ascii).should == "Arço" end end diff --git a/spec/ruby/core/string/delete_prefix_spec.rb b/spec/ruby/core/string/delete_prefix_spec.rb index a063e443d8d83a..17ce18bccad8bb 100644 --- a/spec/ruby/core/string/delete_prefix_spec.rb +++ b/spec/ruby/core/string/delete_prefix_spec.rb @@ -21,6 +21,10 @@ r.should == s end + it "does not remove partial bytes, only full characters" do + "\xe3\x81\x82".delete_prefix("\xe3").should == "\xe3\x81\x82" + end + it "doesn't set $~" do $~ = nil diff --git a/spec/ruby/core/string/delete_suffix_spec.rb b/spec/ruby/core/string/delete_suffix_spec.rb index 3d3274bc5b7e89..0705c732463a82 100644 --- a/spec/ruby/core/string/delete_suffix_spec.rb +++ b/spec/ruby/core/string/delete_suffix_spec.rb @@ -21,6 +21,10 @@ r.should == s end + it "does not remove partial bytes, only full characters" do + "\xe3\x81\x82".delete_suffix("\x82").should == "\xe3\x81\x82" + end + it "doesn't set $~" do $~ = nil diff --git a/spec/ruby/core/string/downcase_spec.rb b/spec/ruby/core/string/downcase_spec.rb index 86d84808890662..f0a15f1e25f120 100644 --- a/spec/ruby/core/string/downcase_spec.rb +++ b/spec/ruby/core/string/downcase_spec.rb @@ -27,6 +27,10 @@ it "does not downcase non-ASCII characters" do "Câ„«R".downcase(:ascii).should == "câ„«r" end + + it "works with substrings" do + "prefix TÉ"[-2..-1].downcase(:ascii).should == "tÉ" + end end describe "full Unicode case mapping adapted for Turkic languages" do diff --git a/spec/ruby/core/string/encoding_spec.rb b/spec/ruby/core/string/encoding_spec.rb index 4d17a39f29427f..574a1e2f9287df 100644 --- a/spec/ruby/core/string/encoding_spec.rb +++ b/spec/ruby/core/string/encoding_spec.rb @@ -10,6 +10,7 @@ it "is equal to the source encoding by default" do s = StringSpecs::ISO88599Encoding.new s.cedilla.encoding.should == s.source_encoding + s.cedilla.encode("utf-8").should == 350.chr(Encoding::UTF_8) # S-cedilla end it "returns the given encoding if #force_encoding has been called" do diff --git a/spec/ruby/core/string/fixtures/iso-8859-9-encoding.rb b/spec/ruby/core/string/fixtures/iso-8859-9-encoding.rb index 61a691ff789d65..cfa91dedc3a641 100644 --- a/spec/ruby/core/string/fixtures/iso-8859-9-encoding.rb +++ b/spec/ruby/core/string/fixtures/iso-8859-9-encoding.rb @@ -4,6 +4,6 @@ class ISO88599Encoding def source_encoding; __ENCODING__; end def x_escape; [0xDF].pack('C').force_encoding("iso-8859-9"); end def ascii_only; "glark"; end - def cedilla; "Åž"; end + def cedilla; "Þ"; end # S-cedilla end end diff --git a/spec/ruby/core/string/include_spec.rb b/spec/ruby/core/string/include_spec.rb index e32eb17c29e2b6..23e1e134ec73f3 100644 --- a/spec/ruby/core/string/include_spec.rb +++ b/spec/ruby/core/string/include_spec.rb @@ -13,6 +13,20 @@ StringSpecs::MyString.new("hello").include?(StringSpecs::MyString.new("lo")).should == true end + it "returns true if both strings are empty" do + "".should.include?("") + "".force_encoding("EUC-JP").should.include?("") + "".should.include?("".force_encoding("EUC-JP")) + "".force_encoding("EUC-JP").should.include?("".force_encoding("EUC-JP")) + end + + it "returns true if the RHS is empty" do + "a".should.include?("") + "a".force_encoding("EUC-JP").should.include?("") + "a".should.include?("".force_encoding("EUC-JP")) + "a".force_encoding("EUC-JP").should.include?("".force_encoding("EUC-JP")) + end + it "tries to convert other to string using to_str" do other = mock('lo') other.should_receive(:to_str).and_return("lo") diff --git a/spec/ruby/core/string/inspect_spec.rb b/spec/ruby/core/string/inspect_spec.rb index 8bfd465144d6b4..8bf3d3161fba7c 100644 --- a/spec/ruby/core/string/inspect_spec.rb +++ b/spec/ruby/core/string/inspect_spec.rb @@ -19,6 +19,21 @@ ].should be_computed_by(:inspect) end + it "returns a string with special characters replaced with \\ notation for UTF-16" do + pairs = [ + ["\a", '"\\a"'], + ["\b", '"\\b"'], + ["\t", '"\\t"'], + ["\n", '"\\n"'], + ["\v", '"\\v"'], + ["\f", '"\\f"'], + ["\r", '"\\r"'], + ["\e", '"\\e"'] + ].map { |str, result| [str.encode('UTF-16LE'), result] } + + pairs.should be_computed_by(:inspect) + end + it "returns a string with \" and \\ escaped with a backslash" do [ ["\"", '"\\""'], ["\\", '"\\\\"'] @@ -311,6 +326,11 @@ "\xF0\x9F".inspect.should == '"\\xF0\\x9F"' end + it "works for broken US-ASCII strings" do + s = "©".force_encoding("US-ASCII") + s.inspect.should == '"\xC2\xA9"' + end + describe "when default external is UTF-8" do before :each do @extenc, Encoding.default_external = Encoding.default_external, Encoding::UTF_8 diff --git a/spec/ruby/core/string/lstrip_spec.rb b/spec/ruby/core/string/lstrip_spec.rb index 02bc6b4322f6be..75434613f18bac 100644 --- a/spec/ruby/core/string/lstrip_spec.rb +++ b/spec/ruby/core/string/lstrip_spec.rb @@ -10,6 +10,14 @@ " hello world ".lstrip.should == "hello world " "\n\r\t\n\v\r hello world ".lstrip.should == "hello world " "hello".lstrip.should == "hello" + " ã“ã«ã¡ã‚".lstrip.should == "ã“ã«ã¡ã‚" + end + + it "works with lazy substrings" do + " hello "[1...-1].lstrip.should == "hello " + " hello world "[1...-1].lstrip.should == "hello world " + "\n\r\t\n\v\r hello world "[1...-1].lstrip.should == "hello world " + " ã“ã«ã¡ã‚ "[1...-1].lstrip.should == "ã“ã«ã¡ã‚" end ruby_version_is '3.0' do @@ -27,20 +35,26 @@ a.should == "hello " end + it "returns nil if no modifications were made" do + a = "hello" + a.lstrip!.should == nil + a.should == "hello" + end + + it "makes a string empty if it is only whitespace" do + "".lstrip!.should == nil + " ".lstrip.should == "" + " ".lstrip.should == "" + end + ruby_version_is '3.0' do - it "strips leading \\0" do + it "removes leading NULL bytes and whitespace" do a = "\000 \000hello\000 \000" a.lstrip! a.should == "hello\000 \000" end end - it "returns nil if no modifications were made" do - a = "hello" - a.lstrip!.should == nil - a.should == "hello" - end - it "raises a FrozenError on a frozen instance that is modified" do -> { " hello ".freeze.lstrip! }.should raise_error(FrozenError) end @@ -51,9 +65,13 @@ -> { "".freeze.lstrip! }.should raise_error(FrozenError) end - it "raises an ArgumentError if the first codepoint is invalid" do + it "raises an ArgumentError if the first non-space codepoint is invalid" do s = "\xDFabc".force_encoding(Encoding::UTF_8) s.valid_encoding?.should be_false -> { s.lstrip! }.should raise_error(ArgumentError) + + s = " \xDFabc".force_encoding(Encoding::UTF_8) + s.valid_encoding?.should be_false + -> { s.lstrip! }.should raise_error(ArgumentError) end end diff --git a/spec/ruby/core/string/ord_spec.rb b/spec/ruby/core/string/ord_spec.rb index cfc630a1249d83..4cf26990fedec8 100644 --- a/spec/ruby/core/string/ord_spec.rb +++ b/spec/ruby/core/string/ord_spec.rb @@ -25,4 +25,9 @@ it "raises an ArgumentError if called on an empty String" do -> { ''.ord }.should raise_error(ArgumentError) end + + it "raises ArgumentError if the character is broken" do + s = "©".force_encoding("US-ASCII") + -> { s.ord }.should raise_error(ArgumentError, "invalid byte sequence in US-ASCII") + end end diff --git a/spec/ruby/core/string/reverse_spec.rb b/spec/ruby/core/string/reverse_spec.rb index bade4685d9966e..4206b8af90b7f4 100644 --- a/spec/ruby/core/string/reverse_spec.rb +++ b/spec/ruby/core/string/reverse_spec.rb @@ -29,6 +29,14 @@ it "reverses a string with multi byte characters" do "微軟正黑體".reverse.should == "體黑正軟微" end + + it "works with a broken string" do + str = "微軟\xDF\xDE正黑體".force_encoding(Encoding::UTF_8) + + str.valid_encoding?.should be_false + + str.reverse.should == "體黑正\xDE\xDF軟微" + end end describe "String#reverse!" do @@ -55,4 +63,13 @@ str.reverse! str.should == "體黑正軟微" end + + it "works with a broken string" do + str = "微軟\xDF\xDE正黑體".force_encoding(Encoding::UTF_8) + + str.valid_encoding?.should be_false + str.reverse! + + str.should == "體黑正\xDE\xDF軟微" + end end diff --git a/spec/ruby/core/string/rstrip_spec.rb b/spec/ruby/core/string/rstrip_spec.rb index dc34b12719ed9d..4332b33b20046f 100644 --- a/spec/ruby/core/string/rstrip_spec.rb +++ b/spec/ruby/core/string/rstrip_spec.rb @@ -11,6 +11,14 @@ " hello world \n\r\t\n\v\r".rstrip.should == " hello world" "hello".rstrip.should == "hello" "hello\x00".rstrip.should == "hello" + "ã“ã«ã¡ã‚ ".rstrip.should == "ã“ã«ã¡ã‚" + end + + it "works with lazy substrings" do + " hello "[1...-1].rstrip.should == " hello" + " hello world "[1...-1].rstrip.should == " hello world" + " hello world \n\r\t\n\v\r"[1...-1].rstrip.should == " hello world" + " ã“ã«ã¡ã‚ "[1...-1].rstrip.should == "ã“ã«ã¡ã‚" end it "returns a copy of self with all trailing whitespace and NULL bytes removed" do @@ -37,6 +45,20 @@ a.should == "hello" end + it "makes a string empty if it is only whitespace" do + "".rstrip!.should == nil + " ".rstrip.should == "" + " ".rstrip.should == "" + end + + ruby_version_is '3.0' do + it "removes trailing NULL bytes and whitespace" do + a = "\000 goodbye \000" + a.rstrip! + a.should == "\000 goodbye" + end + end + it "raises a FrozenError on a frozen instance that is modified" do -> { " hello ".freeze.rstrip! }.should raise_error(FrozenError) end @@ -47,9 +69,13 @@ -> { "".freeze.rstrip! }.should raise_error(FrozenError) end - it "raises an ArgumentError if the last codepoint is invalid" do + it "raises an ArgumentError if the last non-space codepoint is invalid" do s = "abc\xDF".force_encoding(Encoding::UTF_8) s.valid_encoding?.should be_false -> { s.rstrip! }.should raise_error(ArgumentError) + + s = "abc\xDF ".force_encoding(Encoding::UTF_8) + s.valid_encoding?.should be_false + -> { s.rstrip! }.should raise_error(ArgumentError) end end diff --git a/spec/ruby/core/string/setbyte_spec.rb b/spec/ruby/core/string/setbyte_spec.rb index 03e5bad88b7c57..77bff6403850f6 100644 --- a/spec/ruby/core/string/setbyte_spec.rb +++ b/spec/ruby/core/string/setbyte_spec.rb @@ -36,6 +36,12 @@ str.valid_encoding?.should be_true str.setbyte(2,253) str.valid_encoding?.should be_false + + str = "ABC" + str.setbyte(0, 0x20) # ' ' + str.should.valid_encoding? + str.setbyte(0, 0xE3) + str.should_not.valid_encoding? end it "regards a negative index as counting from the end of the String" do diff --git a/spec/ruby/core/string/shared/dedup.rb b/spec/ruby/core/string/shared/dedup.rb index 345e8745835c54..6ffcb9b04553a7 100644 --- a/spec/ruby/core/string/shared/dedup.rb +++ b/spec/ruby/core/string/shared/dedup.rb @@ -38,6 +38,16 @@ dynamic.send(@method).should equal("this string is frozen".send(@method).freeze) end + it "does not deduplicate a frozen string when it has instance variables" do + dynamic = %w(this string is frozen).join(' ') + dynamic.instance_variable_set(:@a, 1) + dynamic.freeze + + dynamic.send(@method).should_not equal("this string is frozen".freeze) + dynamic.send(@method).should_not equal("this string is frozen".send(@method).freeze) + dynamic.send(@method).should equal(dynamic) + end + ruby_version_is "3.0" do it "interns the provided string if it is frozen" do dynamic = "this string is unique and frozen #{rand}".freeze diff --git a/spec/ruby/core/string/split_spec.rb b/spec/ruby/core/string/split_spec.rb index 7ef34c65daae48..b57f6608166302 100644 --- a/spec/ruby/core/string/split_spec.rb +++ b/spec/ruby/core/string/split_spec.rb @@ -455,6 +455,14 @@ a.should == ["Chunky", "Bacon"] end + it "yields each split substring with default pattern for a lazy substring" do + a = [] + returned_object = "chunky bacon"[1...-1].split { |str| a << str.capitalize } + + returned_object.should == "hunky baco" + a.should == ["Hunky", "Baco"] + end + it "yields each split substring with default pattern for a non-ASCII string" do a = [] returned_object = "l'été arrive bientôt".split { |str| a << str } @@ -463,6 +471,14 @@ a.should == ["l'été", "arrive", "bientôt"] end + it "yields each split substring with default pattern for a non-ASCII lazy substring" do + a = [] + returned_object = "l'été arrive bientôt"[1...-1].split { |str| a << str } + + returned_object.should == "'été arrive bientô" + a.should == ["'été", "arrive", "bientô"] + end + it "yields the string when limit is 1" do a = [] returned_object = "chunky bacon".split("", 1) { |str| a << str.capitalize } diff --git a/spec/ruby/core/string/start_with_spec.rb b/spec/ruby/core/string/start_with_spec.rb index aaed197ff372a3..3833289f96d488 100644 --- a/spec/ruby/core/string/start_with_spec.rb +++ b/spec/ruby/core/string/start_with_spec.rb @@ -5,4 +5,14 @@ describe "String#start_with?" do it_behaves_like :start_with, :to_s + + # Here and not in the shared examples because this is invalid as a Symbol + it "does not check that we are not starting to match at the head of a character" do + "\xA9".should.start_with?("\xA9") # A9 is not a character head for UTF-8 + end + + it "does not check we are matching only part of a character" do + "\xe3\x81\x82".size.should == 1 + "\xe3\x81\x82".should.start_with?("\xe3") + end end diff --git a/spec/ruby/core/string/strip_spec.rb b/spec/ruby/core/string/strip_spec.rb index e841db54ce401b..662f13b03219c7 100644 --- a/spec/ruby/core/string/strip_spec.rb +++ b/spec/ruby/core/string/strip_spec.rb @@ -35,6 +35,12 @@ a.should == "hello" end + it "makes a string empty if it is only whitespace" do + "".strip!.should == nil + " ".strip.should == "" + " ".strip.should == "" + end + ruby_version_is '3.0' do it "removes leading and trailing NULL bytes and whitespace" do a = "\000 goodbye \000" diff --git a/spec/ruby/core/string/swapcase_spec.rb b/spec/ruby/core/string/swapcase_spec.rb index 417f6c6d8d76b2..6307a1eaafe602 100644 --- a/spec/ruby/core/string/swapcase_spec.rb +++ b/spec/ruby/core/string/swapcase_spec.rb @@ -28,6 +28,10 @@ it "does not swapcase non-ASCII characters" do "aßet".swapcase(:ascii).should == "AßET" end + + it "works with substrings" do + "prefix aTé"[-3..-1].swapcase(:ascii).should == "Até" + end end describe "full Unicode case mapping adapted for Turkic languages" do diff --git a/spec/ruby/core/string/upcase_spec.rb b/spec/ruby/core/string/upcase_spec.rb index b2b34190feaab8..209fe73b6ec985 100644 --- a/spec/ruby/core/string/upcase_spec.rb +++ b/spec/ruby/core/string/upcase_spec.rb @@ -27,6 +27,10 @@ it "does not upcase non-ASCII characters" do "aßet".upcase(:ascii).should == "AßET" end + + it "works with substrings" do + "prefix té"[-2..-1].upcase(:ascii).should == "Té" + end end describe "full Unicode case mapping adapted for Turkic languages" do diff --git a/spec/ruby/language/range_spec.rb b/spec/ruby/language/range_spec.rb index 55dc65882a9e2a..ccc9f55537d5fd 100644 --- a/spec/ruby/language/range_spec.rb +++ b/spec/ruby/language/range_spec.rb @@ -10,6 +10,14 @@ (1...10).should == Range.new(1, 10, true) end + it "creates a simple range as an object literal" do + ary = [] + 2.times do + ary.push(1..3) + end + ary[0].should.equal?(ary[1]) + end + it "creates endless ranges" do (1..).should == Range.new(1, nil) (1...).should == Range.new(1, nil, true) diff --git a/spec/ruby/language/regexp/escapes_spec.rb b/spec/ruby/language/regexp/escapes_spec.rb index 2e5fe5ad2e64fa..16a4d8c23b2bf6 100644 --- a/spec/ruby/language/regexp/escapes_spec.rb +++ b/spec/ruby/language/regexp/escapes_spec.rb @@ -2,8 +2,10 @@ require_relative '../../spec_helper' require_relative '../fixtures/classes' +# TODO: synchronize with spec/core/regexp/new_spec.rb - +# escaping is also tested there describe "Regexps with escape characters" do - it "they're supported" do + it "supports escape sequences" do /\t/.match("\t").to_a.should == ["\t"] # horizontal tab /\v/.match("\v").to_a.should == ["\v"] # vertical tab /\n/.match("\n").to_a.should == ["\n"] # newline @@ -15,9 +17,7 @@ # \nnn octal char (encoded byte value) end - it "support quoting meta-characters via escape sequence" do - /\\/.match("\\").to_a.should == ["\\"] - /\//.match("/").to_a.should == ["/"] + it "supports quoting meta-characters via escape sequence" do # parenthesis, etc /\(/.match("(").to_a.should == ["("] /\)/.match(")").to_a.should == [")"] @@ -25,6 +25,8 @@ /\]/.match("]").to_a.should == ["]"] /\{/.match("{").to_a.should == ["{"] /\}/.match("}").to_a.should == ["}"] + /\/.match(">").to_a.should == [">"] # alternation separator /\|/.match("|").to_a.should == ["|"] # quantifiers @@ -37,11 +39,81 @@ /\$/.match("$").to_a.should == ["$"] end + it "supports quoting meta-characters via escape sequence when used as a terminator" do + # parenthesis, etc + # %r[[, %r((, etc literals - are forbidden + %r(\().match("(").to_a.should == ["("] + %r(\)).match(")").to_a.should == [")"] + %r)\().match("(").to_a.should == ["("] + %r)\)).match(")").to_a.should == [")"] + + %r[\[].match("[").to_a.should == ["["] + %r[\]].match("]").to_a.should == ["]"] + %r]\[].match("[").to_a.should == ["["] + %r]\]].match("]").to_a.should == ["]"] + + %r{\{}.match("{").to_a.should == ["{"] + %r{\}}.match("}").to_a.should == ["}"] + %r}\{}.match("{").to_a.should == ["{"] + %r}\}}.match("}").to_a.should == ["}"] + + %r<\<>.match("<").to_a.should == ["<"] + %r<\>>.match(">").to_a.should == [">"] + %r>\<>.match("<").to_a.should == ["<"] + %r>\>>.match(">").to_a.should == [">"] + + # alternation separator + %r|\||.match("|").to_a.should == ["|"] + # quantifiers + %r?\??.match("?").to_a.should == ["?"] + %r.\...match(".").to_a.should == ["."] + %r*\**.match("*").to_a.should == ["*"] + %r+\++.match("+").to_a.should == ["+"] + # line anchors + %r^\^^.match("^").to_a.should == ["^"] + %r$\$$.match("$").to_a.should == ["$"] + end + + it "supports quoting non-meta-characters via escape sequence when used as a terminator" do + non_meta_character_terminators = [ + '!', '"', '#', '%', '&', "'", ',', '-', ':', ';', '@', '_', '`', '/', '=', '~' + ] + + non_meta_character_terminators.each do |c| + pattern = eval("%r" + c + "\\" + c + c) + pattern.match(c).to_a.should == [c] + end + end + + it "does not change semantics of escaped non-meta-character when used as a terminator" do + all_terminators = [*("!".."/"), *(":".."@"), *("[".."`"), *("{".."~")] + meta_character_terminators = ["$", "^", "*", "+", ".", "?", "|", "}", ")", ">", "]"] + special_cases = ['(', '{', '[', '<', '\\'] + + # it should be equivalent to + # [ '!', '"', '#', '%', '&', "'", ',', '-', ':', ';', '@', '_', '`', '/', '=', '~' ] + non_meta_character_terminators = all_terminators - meta_character_terminators - special_cases + + non_meta_character_terminators.each do |c| + pattern = eval("%r" + c + "\\" + c + c) + pattern.should == /#{c}/ + end + end + + it "does not change semantics of escaped meta-character when used as a terminator" do + meta_character_terminators = ["$", "^", "*", "+", ".", "?", "|", "}", ")", ">", "]"] + + meta_character_terminators.each do |c| + pattern = eval("%r" + c + "\\" + c + c) + pattern.should == eval("/\\#{c}/") + end + end + it "allows any character to be escaped" do /\y/.match("y").to_a.should == ["y"] end - it "support \\x (hex characters)" do + it "supports \\x (hex characters)" do /\xA/.match("\nxyz").to_a.should == ["\n"] /\x0A/.match("\n").to_a.should == ["\n"] /\xAA/.match("\nA").should be_nil @@ -53,7 +125,7 @@ # \x{7HHHHHHH} wide hexadecimal char (character code point value) end - it "support \\c (control characters)" do + it "supports \\c (control characters)" do #/\c \c@\c`/.match("\00\00\00").to_a.should == ["\00\00\00"] /\c#\cc\cC/.match("\03\03\03").to_a.should == ["\03\03\03"] /\c'\cG\cg/.match("\a\a\a").to_a.should == ["\a\a\a"] diff --git a/spec/ruby/language/regexp_spec.rb b/spec/ruby/language/regexp_spec.rb index 8fc4dc4f0a8973..d49689349dd08c 100644 --- a/spec/ruby/language/regexp_spec.rb +++ b/spec/ruby/language/regexp_spec.rb @@ -96,7 +96,6 @@ /./.match("\0").to_a.should == ["\0"] end - it "supports | (alternations)" do /a|b/.match("a").to_a.should == ["a"] end @@ -161,26 +160,6 @@ pattern.should_not =~ 'T' end - escapable_terminators = ['!', '"', '#', '%', '&', "'", ',', '-', ':', ';', '@', '_', '`'] - - it "supports escaping characters when used as a terminator" do - escapable_terminators.each do |c| - ref = "(?-mix:#{c})" - pattern = eval("%r" + c + "\\" + c + c) - pattern.to_s.should == ref - end - end - - it "treats an escaped non-escapable character normally when used as a terminator" do - all_terminators = [*("!".."/"), *(":".."@"), *("[".."`"), *("{".."~")] - special_cases = ['(', '{', '[', '<', '\\', '=', '~'] - (all_terminators - special_cases - escapable_terminators).each do |c| - ref = "(?-mix:\\#{c})" - pattern = eval("%r" + c + "\\" + c + c) - pattern.to_s.should == ref - end - end - it "support handling unicode 9.0 characters with POSIX bracket expressions" do char_lowercase = "\u{104D8}" # OSAGE SMALL LETTER A /[[:lower:]]/.match(char_lowercase).to_s.should == char_lowercase diff --git a/spec/ruby/library/stringio/shared/read.rb b/spec/ruby/library/stringio/shared/read.rb index c60677bba75f05..252a85d89d9042 100644 --- a/spec/ruby/library/stringio/shared/read.rb +++ b/spec/ruby/library/stringio/shared/read.rb @@ -89,6 +89,12 @@ @io.send(@method) @io.pos.should eql(7) end + + it "correctly update the current position in bytes when multi-byte characters are used" do + @io.print("example\u03A3") # Overwrite the original string with 8 characters containing 9 bytes. + @io.send(@method) + @io.pos.should eql(9) + end end describe :stringio_read_nil, shared: true do diff --git a/spec/ruby/optional/capi/encoding_spec.rb b/spec/ruby/optional/capi/encoding_spec.rb index e18108c022fcb3..ae557b03d76a0a 100644 --- a/spec/ruby/optional/capi/encoding_spec.rb +++ b/spec/ruby/optional/capi/encoding_spec.rb @@ -128,10 +128,16 @@ describe "rb_enc_mbc_to_codepoint" do it "returns the correct codepoint for the given character and size" do - @s.rb_enc_mbc_to_codepoint("é", 2).should == 0x00E9 - @s.rb_enc_mbc_to_codepoint("éa", 2).should == 0x00E9 - @s.rb_enc_mbc_to_codepoint("éa", 1).should == 0xC3 - @s.rb_enc_mbc_to_codepoint("éa", 3).should == 0x00E9 + @s.rb_enc_mbc_to_codepoint("é").should == 0xE9 + end + + it "returns 0 if p == e" do + @s.rb_enc_mbc_to_codepoint("").should == 0 + end + + it "returns the raw byte if incomplete character in UTF-8" do + @s.rb_enc_mbc_to_codepoint("\xC3").should == 0xC3 + @s.rb_enc_mbc_to_codepoint("\x80").should == 0x80 end end @@ -630,6 +636,7 @@ it "returns the correct case fold for the given string" do @s.ONIGENC_MBC_CASE_FOLD("lower").should == ["l", 1] @s.ONIGENC_MBC_CASE_FOLD("Upper").should == ["u", 1] + @s.ONIGENC_MBC_CASE_FOLD("ABC"[1..-1]).should == ["b", 1] end it "works with other encodings" do diff --git a/spec/ruby/optional/capi/ext/encoding_spec.c b/spec/ruby/optional/capi/ext/encoding_spec.c index 68c4161bab0c43..c49f6cde7e6e00 100644 --- a/spec/ruby/optional/capi/ext/encoding_spec.c +++ b/spec/ruby/optional/capi/ext/encoding_spec.c @@ -120,10 +120,9 @@ static VALUE encoding_spec_rb_enc_from_index(VALUE self, VALUE index) { return rb_str_new2(rb_enc_from_index(NUM2INT(index))->name); } -static VALUE encoding_spec_rb_enc_mbc_to_codepoint(VALUE self, VALUE str, VALUE offset) { - int o = FIX2INT(offset); +static VALUE encoding_spec_rb_enc_mbc_to_codepoint(VALUE self, VALUE str) { char *p = RSTRING_PTR(str); - char *e = p + o; + char *e = RSTRING_END(str); return INT2FIX(rb_enc_mbc_to_codepoint(p, e, rb_enc_get(str))); } @@ -341,7 +340,7 @@ void Init_encoding_spec(void) { rb_define_method(cls, "rb_enc_isalnum", encoding_spec_rb_enc_isalnum, 2); rb_define_method(cls, "rb_enc_isspace", encoding_spec_rb_enc_isspace, 2); rb_define_method(cls, "rb_enc_from_index", encoding_spec_rb_enc_from_index, 1); - rb_define_method(cls, "rb_enc_mbc_to_codepoint", encoding_spec_rb_enc_mbc_to_codepoint, 2); + rb_define_method(cls, "rb_enc_mbc_to_codepoint", encoding_spec_rb_enc_mbc_to_codepoint, 1); rb_define_method(cls, "rb_enc_mbcput", encoding_spec_rb_enc_mbcput, 2); rb_define_method(cls, "rb_enc_from_encoding", encoding_spec_rb_enc_from_encoding, 1); rb_define_method(cls, "rb_enc_get", encoding_spec_rb_enc_get, 1); diff --git a/spec/ruby/shared/file/executable.rb b/spec/ruby/shared/file/executable.rb index 7b5c4c580c2bf7..baa156de9862dd 100644 --- a/spec/ruby/shared/file/executable.rb +++ b/spec/ruby/shared/file/executable.rb @@ -39,6 +39,41 @@ -> { @object.send(@method, nil) }.should raise_error(TypeError) -> { @object.send(@method, false) }.should raise_error(TypeError) end + + platform_is_not :windows do + as_superuser do + context "when run by a superuser" do + before :each do + @file = tmp('temp3.txt') + touch @file + end + + after :each do + rm_r @file + end + + it "returns true if file owner has permission to execute" do + File.chmod(0766, @file) + @object.send(@method, @file).should == true + end + + it "returns true if group has permission to execute" do + File.chmod(0676, @file) + @object.send(@method, @file).should == true + end + + it "returns true if other have permission to execute" do + File.chmod(0667, @file) + @object.send(@method, @file).should == true + end + + it "return false if nobody has permission to execute" do + File.chmod(0666, @file) + @object.send(@method, @file).should == false + end + end + end + end end describe :file_executable_missing, shared: true do diff --git a/spec/ruby/shared/file/executable_real.rb b/spec/ruby/shared/file/executable_real.rb index ce3d5ca1768dc3..bf2734ea071fdf 100644 --- a/spec/ruby/shared/file/executable_real.rb +++ b/spec/ruby/shared/file/executable_real.rb @@ -37,6 +37,41 @@ -> { @object.send(@method, nil) }.should raise_error(TypeError) -> { @object.send(@method, false) }.should raise_error(TypeError) end + + platform_is_not :windows do + as_real_superuser do + context "when run by a real superuser" do + before :each do + @file = tmp('temp3.txt') + touch @file + end + + after :each do + rm_r @file + end + + it "returns true if file owner has permission to execute" do + File.chmod(0766, @file) + @object.send(@method, @file).should == true + end + + it "returns true if group has permission to execute" do + File.chmod(0676, @file) + @object.send(@method, @file).should == true + end + + it "returns true if other have permission to execute" do + File.chmod(0667, @file) + @object.send(@method, @file).should == true + end + + it "return false if nobody has permission to execute" do + File.chmod(0666, @file) + @object.send(@method, @file).should == false + end + end + end + end end describe :file_executable_real_missing, shared: true do diff --git a/spec/ruby/shared/file/readable.rb b/spec/ruby/shared/file/readable.rb index eb2ca068121823..7b45e23e3607e1 100644 --- a/spec/ruby/shared/file/readable.rb +++ b/spec/ruby/shared/file/readable.rb @@ -24,6 +24,22 @@ it "accepts an object that has a #to_path method" do @object.send(@method, mock_to_path(@file2)).should == true end + + platform_is_not :windows do + as_superuser do + context "when run by a superuser" do + it "returns true unconditionally" do + file = tmp('temp.txt') + touch file + + File.chmod(0333, file) + @object.send(@method, file).should == true + + rm_r file + end + end + end + end end describe :file_readable_missing, shared: true do diff --git a/spec/ruby/shared/file/readable_real.rb b/spec/ruby/shared/file/readable_real.rb index b6e53ac76d7579..32d38bc7a23fb5 100644 --- a/spec/ruby/shared/file/readable_real.rb +++ b/spec/ruby/shared/file/readable_real.rb @@ -14,6 +14,22 @@ it "accepts an object that has a #to_path method" do File.open(@file,'w') { @object.send(@method, mock_to_path(@file)).should == true } end + + platform_is_not :windows do + as_real_superuser do + context "when run by a real superuser" do + it "returns true unconditionally" do + file = tmp('temp.txt') + touch file + + File.chmod(0333, file) + @object.send(@method, file).should == true + + rm_r file + end + end + end + end end describe :file_readable_real_missing, shared: true do diff --git a/spec/ruby/shared/file/writable.rb b/spec/ruby/shared/file/writable.rb index 4bb8aedce6840b..65ea2c1781a6d7 100644 --- a/spec/ruby/shared/file/writable.rb +++ b/spec/ruby/shared/file/writable.rb @@ -19,6 +19,22 @@ it "accepts an object that has a #to_path method" do File.open(@file,'w') { @object.send(@method, mock_to_path(@file)).should == true } end + + platform_is_not :windows do + as_superuser do + context "when run by a superuser" do + it "returns true unconditionally" do + file = tmp('temp.txt') + touch file + + File.chmod(0555, file) + @object.send(@method, file).should == true + + rm_r file + end + end + end + end end describe :file_writable_missing, shared: true do diff --git a/spec/ruby/shared/file/writable_real.rb b/spec/ruby/shared/file/writable_real.rb index e9721fd379b88e..b4a0a58c6e4391 100644 --- a/spec/ruby/shared/file/writable_real.rb +++ b/spec/ruby/shared/file/writable_real.rb @@ -24,6 +24,22 @@ -> { @object.send(@method, nil) }.should raise_error(TypeError) -> { @object.send(@method, false) }.should raise_error(TypeError) end + + platform_is_not :windows do + as_real_superuser do + context "when run by a real superuser" do + it "returns true unconditionally" do + file = tmp('temp.txt') + touch file + + File.chmod(0555, file) + @object.send(@method, file).should == true + + rm_r file + end + end + end + end end describe :file_writable_real_missing, shared: true do diff --git a/spec/ruby/shared/queue/deque.rb b/spec/ruby/shared/queue/deque.rb index 8b755dd9b7a1ee..ed32bd29c88b61 100644 --- a/spec/ruby/shared/queue/deque.rb +++ b/spec/ruby/shared/queue/deque.rb @@ -55,6 +55,61 @@ t.join end + describe "with a timeout" do + ruby_version_is "3.2" do + it "returns an item if one is available in time" do + q = @object.call + + t = Thread.new { + q.send(@method, timeout: 1).should == 1 + } + Thread.pass until t.status == "sleep" && q.num_waiting == 1 + q << 1 + t.join + end + + it "returns nil if no item is available in time" do + q = @object.call + + t = Thread.new { + q.send(@method, timeout: 0.1).should == nil + } + t.join + end + + it "does nothing if the timeout is nil" do + q = @object.call + t = Thread.new { + q.send(@method, timeout: nil).should == 1 + } + t.join(0.2).should == nil + q << 1 + t.join + end + + it "raise TypeError if timeout is not a valid numeric" do + q = @object.call + -> { q.send(@method, timeout: "1") }.should raise_error( + TypeError, + "no implicit conversion to float from string", + ) + + -> { q.send(@method, timeout: false) }.should raise_error( + TypeError, + "no implicit conversion to float from false", + ) + end + + it "raise ArgumentError if non_block = true is passed too" do + q = @object.call + -> { q.send(@method, true, timeout: 1) }.should raise_error( + ArgumentError, + "can't set a timeout if non_block is enabled", + ) + end + end + end + describe "in non-blocking mode" do it "removes an item from the queue" do q = @object.call diff --git a/spec/ruby/shared/string/end_with.rb b/spec/ruby/shared/string/end_with.rb index 5f2a0112356517..0e4c1386e8e7eb 100644 --- a/spec/ruby/shared/string/end_with.rb +++ b/spec/ruby/shared/string/end_with.rb @@ -38,7 +38,7 @@ it "uses only the needed arguments" do find = mock('h') find.should_not_receive(:to_str) - "hello".send(@method).should.end_with?("o",find) + "hello".send(@method).should.end_with?("o", find) end it "works for multibyte strings" do @@ -51,4 +51,11 @@ "ã‚れ".send(@method).end_with?(pat) end.should raise_error(Encoding::CompatibilityError) end + + it "checks that we are starting to match at the head of a character" do + "\xC3\xA9".send(@method).should_not.end_with?("\xA9") + "\xe3\x81\x82".send(@method).should_not.end_with?("\x82") + "ab".force_encoding("UTF-16BE").send(@method).should_not.end_with?( + "b".force_encoding("UTF-16BE")) + end end diff --git a/spec/ruby/shared/string/start_with.rb b/spec/ruby/shared/string/start_with.rb index d8d6e13f6ae67a..6932a017b6d621 100644 --- a/spec/ruby/shared/string/start_with.rb +++ b/spec/ruby/shared/string/start_with.rb @@ -69,4 +69,8 @@ Regexp.last_match.should be_nil $1.should be_nil end + + it "does not check that we are not matching part of a character" do + "\xC3\xA9".send(@method).should.start_with?("\xC3") + end end diff --git a/string.c b/string.c index f5e089aa21a4aa..85819e26a393a3 100644 --- a/string.c +++ b/string.c @@ -10779,7 +10779,23 @@ rb_str_b(VALUE str) str2 = str_alloc_embed(rb_cString, RSTRING_EMBED_LEN(str) + TERM_LEN(str)); } str_replace_shared_without_enc(str2, str); - ENC_CODERANGE_CLEAR(str2); + + // BINARY strings can never be broken; they're either 7-bit ASCII or VALID. + // If we know the receiver's code range then we know the result's code range. + int cr = ENC_CODERANGE(str); + switch (cr) { + case ENC_CODERANGE_7BIT: + ENC_CODERANGE_SET(str2, ENC_CODERANGE_7BIT); + break; + case ENC_CODERANGE_BROKEN: + case ENC_CODERANGE_VALID: + ENC_CODERANGE_SET(str2, ENC_CODERANGE_VALID); + break; + default: + ENC_CODERANGE_CLEAR(str2); + break; + } + return str2; } diff --git a/struct.c b/struct.c index d1c8ae24f22300..7085042b43c2b3 100644 --- a/struct.c +++ b/struct.c @@ -115,7 +115,7 @@ struct_set_members(VALUE klass, VALUE /* frozen hidden array */ members) while (mask < members_length * AREF_HASH_UNIT) mask *= 2; - back = rb_ary_tmp_new(mask + 1); + back = rb_ary_hidden_new(mask + 1); rb_ary_store(back, mask, INT2FIX(members_length)); mask -= 2; /* mask = (2**k-1)*2 */ @@ -810,7 +810,7 @@ rb_struct_new(VALUE klass, ...) size = rb_long2int(num_members(klass)); if (size > numberof(tmpargs)) { - tmpargs[0] = rb_ary_tmp_new(size); + tmpargs[0] = rb_ary_hidden_new(size); mem = RARRAY_PTR(tmpargs[0]); } va_start(args, klass); diff --git a/symbol.c b/symbol.c index e89879982f7fc2..6aceab72c1434d 100644 --- a/symbol.c +++ b/symbol.c @@ -91,7 +91,7 @@ Init_sym(void) rb_obj_hide(dsym_fstrs); symbols->str_sym = st_init_table_with_size(&symhash, 1000); - symbols->ids = rb_ary_tmp_new(0); + symbols->ids = rb_ary_hidden_new(0); rb_gc_register_mark_object(symbols->ids); Init_op_tbl(); @@ -426,7 +426,7 @@ set_id_entry(rb_symbols_t *symbols, rb_id_serial_t num, VALUE str, VALUE sym) VALUE ary, ids = symbols->ids; if (idx >= (size_t)RARRAY_LEN(ids) || NIL_P(ary = rb_ary_entry(ids, (long)idx))) { - ary = rb_ary_tmp_new(ID_ENTRY_UNIT * ID_ENTRY_SIZE); + ary = rb_ary_hidden_new(ID_ENTRY_UNIT * ID_ENTRY_SIZE); rb_ary_store(ids, (long)idx, ary); } idx = (num % ID_ENTRY_UNIT) * ID_ENTRY_SIZE; diff --git a/test/-ext-/debug/test_profile_frames.rb b/test/-ext-/debug/test_profile_frames.rb index e0152247e7c245..d6ae953dd298c7 100644 --- a/test/-ext-/debug/test_profile_frames.rb +++ b/test/-ext-/debug/test_profile_frames.rb @@ -137,6 +137,30 @@ def test_profile_frames } end + def test_matches_backtrace_locations_main_thread + assert_equal(Thread.current, Thread.main) + + # Keep these in the same line, so the backtraces match exactly + backtrace_locations, profile_frames = [Thread.current.backtrace_locations, Bug::Debug.profile_frames(0, 100)] + + assert_equal(backtrace_locations.size, profile_frames.size) + + # The first entries are not going to match, since one is #backtrace_locations and the other #profile_frames + backtrace_locations.shift + profile_frames.shift + + # The rest of the stack is expected to look the same... + backtrace_locations.zip(profile_frames).each.with_index do |(location, (path, absolute_path, _, base_label, _, _, _, _, _, _, lineno)), i| + next if absolute_path == "" # ...except for cfunc frames + + err_msg = "#{i}th frame" + assert_equal(location.absolute_path, absolute_path, err_msg) + assert_equal(location.base_label, base_label, err_msg) + assert_equal(location.lineno, lineno, err_msg) + assert_equal(location.path, path, err_msg) + end + end + def test_ifunc_frame bug11851 = '[ruby-core:72409] [Bug #11851]' assert_ruby_status([], <<~'end;', bug11851) # do diff --git a/test/-ext-/eval/test_eval.rb b/test/-ext-/eval/test_eval.rb new file mode 100644 index 00000000000000..27952996e29c90 --- /dev/null +++ b/test/-ext-/eval/test_eval.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: false +require 'test/unit' +require "-test-/eval" + +class EvalTest < Test::Unit::TestCase + def test_rb_eval_string + a = 1 + assert_equal [self, 1, __method__], rb_eval_string(%q{ + [self, a, __method__] + }) + end +end diff --git a/test/io/console/test_io_console.rb b/test/io/console/test_io_console.rb index f6e46fe112bfd4..b5382555f553e8 100644 --- a/test/io/console/test_io_console.rb +++ b/test/io/console/test_io_console.rb @@ -395,7 +395,7 @@ def test_intr assert_ctrl("#{cc.ord}", cc, r, w) assert_ctrl("#{cc.ord}", cc, r, w) end - if cc = ctrl["lnext"] + if (cc = ctrl["lnext"]) && /freebsd/ !~ RUBY_PLATFORM assert_ctrl("#{cc.ord}", cc, r, w) assert_ctrl("#{cc.ord}", cc, r, w) assert_ctrl("#{cc.ord}", cc, r, w) diff --git a/test/json/json_parser_test.rb b/test/json/json_parser_test.rb index 00b254fc6a6941..146ff7c0477f01 100644 --- a/test/json/json_parser_test.rb +++ b/test/json/json_parser_test.rb @@ -115,6 +115,10 @@ def test_parse_bigdecimals assert_equal(BigDecimal("0.901234567890123456789E1"),JSON.parse('{"foo": 9.01234567890123456789}', decimal_class: BigDecimal)["foo"] ) end + def test_parse_string_mixed_unicode + assert_equal(["éé"], JSON.parse("[\"\\u00e9é\"]")) + end + if Array.method_defined?(:permutation) def test_parse_more_complex_arrays a = [ nil, false, true, "foßbar", [ "n€st€d", true ], { "nested" => true, "nۧt€ð2" => {} }] diff --git a/test/optparse/test_placearg.rb b/test/optparse/test_placearg.rb index 94cfb0e819b3e6..ed0e4d3e6c61e0 100644 --- a/test/optparse/test_placearg.rb +++ b/test/optparse/test_placearg.rb @@ -18,6 +18,8 @@ def setup def test_short assert_equal(%w"", no_error {@opt.parse!(%w"-x -n")}) assert_equal(nil, @flag) + assert_equal(%w"", no_error {@opt.parse!(%w"-x -")}) + assert_equal("-", @flag) @flag = false assert_equal(%w"", no_error {@opt.parse!(%w"-x foo")}) assert_equal("foo", @flag) @@ -30,6 +32,8 @@ def test_short def test_abbrev assert_equal(%w"", no_error {@opt.parse!(%w"-o -n")}) assert_equal(nil, @flag) + assert_equal(%w"", no_error {@opt.parse!(%w"-o -")}) + assert_equal("-", @flag) @flag = false assert_equal(%w"", no_error {@opt.parse!(%w"-o foo")}) assert_equal("foo", @flag) @@ -42,6 +46,8 @@ def test_abbrev def test_long assert_equal(%w"", no_error {@opt.parse!(%w"--opt -n")}) assert_equal(nil, @flag) + assert_equal(%w"", no_error {@opt.parse!(%w"--opt -")}) + assert_equal("-", @flag) assert_equal(%w"foo", no_error {@opt.parse!(%w"--opt= foo")}) assert_equal("", @flag) assert_equal(%w"", no_error {@opt.parse!(%w"--opt=foo")}) diff --git a/test/rdoc/test_rdoc_markup_to_html.rb b/test/rdoc/test_rdoc_markup_to_html.rb index e5d7a35710678e..a5927dccaee92e 100644 --- a/test/rdoc/test_rdoc_markup_to_html.rb +++ b/test/rdoc/test_rdoc_markup_to_html.rb @@ -812,6 +812,26 @@ def test_list_verbatim_2 assert_equal expected, @m.convert(str, @to) end + def test_block_quote_in_verbatim + str = "BlockQuote\n >>>\n" + + expected = <<-EXPECTED +

BlockQuote

+
>>>
+ EXPECTED + + assert_equal expected, @m.convert(str, @to).gsub(/^\n/, "") + + str = "BlockQuote\n >>> word\n" + + expected = <<-EXPECTED +

BlockQuote

+
>>>  word
+ EXPECTED + + assert_equal expected, @m.convert(str, @to).gsub(/^\n/, "") + end + def test_parseable_eh valid_syntax = [ 'def x() end', diff --git a/test/ruby/test_enumerator.rb b/test/ruby/test_enumerator.rb index c823b79c6d1126..3ca33126d580dd 100644 --- a/test/ruby/test_enumerator.rb +++ b/test/ruby/test_enumerator.rb @@ -906,4 +906,42 @@ def each(&block) e.chain.each(&->{}) assert_equal(true, e.is_lambda) end + + def test_product + e = Enumerator::Product.new + assert_instance_of(Enumerator::Product, e) + assert_kind_of(Enumerator, e) + assert_equal(1, e.size) + elts = [] + e.each { |*x| elts << x } + assert_equal [[]], elts + + e = Enumerator::Product.new(1..3, %w[a b]) + assert_instance_of(Enumerator::Product, e) + assert_kind_of(Enumerator, e) + assert_equal(3 * 2, e.size) + elts = [] + e.each { |*x| elts << x } + assert_equal [[1, "a"], [1, "b"], [2, "a"], [2, "b"], [3, "a"], [3, "b"]], elts + + e = Enumerator.product(1..3, %w[a b]) + assert_instance_of(Enumerator::Product, e) + + elts = [] + ret = Enumerator.product(1..3, %w[a b]) { |*x| elts << x } + assert_instance_of(Enumerator::Product, ret) + assert_equal [[1, "a"], [1, "b"], [2, "a"], [2, "b"], [3, "a"], [3, "b"]], elts + + e = Enumerator.product(1.., 'a'..'c') + assert_equal(Float::INFINITY, e.size) + assert_equal [[1, "a"], [1, "b"], [1, "c"], [2, "a"]], e.take(4) + + e = Enumerator.product(1.., Enumerator.new { |y| y << 'a' << 'b' }) + assert_equal(Float::INFINITY, e.size) + assert_equal [[1, "a"], [1, "b"], [2, "a"], [2, "b"]], e.take(4) + + e = Enumerator.product(1..3, Enumerator.new { |y| y << 'a' << 'b' }) + assert_equal(nil, e.size) + assert_equal [[1, "a"], [1, "b"], [2, "a"], [2, "b"]], e.take(4) + end end diff --git a/test/ruby/test_env.rb b/test/ruby/test_env.rb index e9eaf144a1eeb2..cdadeac14886e8 100644 --- a/test/ruby/test_env.rb +++ b/test/ruby/test_env.rb @@ -69,25 +69,20 @@ def test_dup end def test_clone - warning = /ENV\.clone is deprecated; use ENV\.to_h instead/ - clone = assert_deprecated_warning(warning) { + message = /Cannot clone ENV/ + assert_raise_with_message(TypeError, message) { ENV.clone } - assert_same(ENV, clone) - - clone = assert_deprecated_warning(warning) { + assert_raise_with_message(TypeError, message) { ENV.clone(freeze: false) } - assert_same(ENV, clone) - - clone = assert_deprecated_warning(warning) { + assert_raise_with_message(TypeError, message) { ENV.clone(freeze: nil) } - assert_same(ENV, clone) - - assert_raise(TypeError) { + assert_raise_with_message(TypeError, message) { ENV.clone(freeze: true) } + assert_raise(ArgumentError) { ENV.clone(freeze: 1) } @@ -688,37 +683,6 @@ def test_dup_in_ractor end; end - def test_clone_in_ractor - assert_ractor(<<-"end;") - r = Ractor.new do - original_warning_state = Warning[:deprecated] - Warning[:deprecated] = false - - begin - Ractor.yield ENV.clone.object_id - Ractor.yield ENV.clone(freeze: false).object_id - Ractor.yield ENV.clone(freeze: nil).object_id - - #{str_for_yielding_exception_class("ENV.clone(freeze: true)")} - #{str_for_yielding_exception_class("ENV.clone(freeze: 1)")} - #{str_for_yielding_exception_class("ENV.clone(foo: false)")} - #{str_for_yielding_exception_class("ENV.clone(1)")} - #{str_for_yielding_exception_class("ENV.clone(1, foo: false)")} - - ensure - Warning[:deprecated] = original_warning_state - end - end - assert_equal(ENV.object_id, r.take) - assert_equal(ENV.object_id, r.take) - assert_equal(ENV.object_id, r.take) - #{str_for_assert_raise_on_yielded_exception_class(TypeError, "r")} - 4.times do - #{str_for_assert_raise_on_yielded_exception_class(ArgumentError, "r")} - end - end; - end - def test_has_value_in_ractor assert_ractor(<<-"end;") r = Ractor.new do diff --git a/test/ruby/test_io.rb b/test/ruby/test_io.rb index b8530e74004f1c..6a3d7594cf04e9 100644 --- a/test/ruby/test_io.rb +++ b/test/ruby/test_io.rb @@ -3114,6 +3114,8 @@ def test_cross_thread_close_fd end def test_cross_thread_close_stdio + omit "[Bug #18613]" if /freebsd/ =~ RUBY_PLATFORM + assert_separately([], <<-'end;') IO.pipe do |r,w| $stdin.reopen(r) @@ -3782,6 +3784,8 @@ def test_race_gets_and_close end def test_race_closed_stream + omit "[Bug #18613]" if /freebsd/ =~ RUBY_PLATFORM + assert_separately([], "#{<<-"begin;"}\n#{<<-"end;"}") begin; bug13158 = '[ruby-core:79262] [Bug #13158]' @@ -3876,6 +3880,8 @@ def lim.to_int; raise "invalid limit"; end end def test_closed_stream_in_rescue + omit "[Bug #18613]" if /freebsd/ =~ RUBY_PLATFORM + assert_separately([], "#{<<-"begin;"}\n#{<<~"end;"}") begin; 10.times do diff --git a/test/ruby/test_settracefunc.rb b/test/ruby/test_settracefunc.rb index 56d457c7d7f4b8..31946c8b719cdb 100644 --- a/test/ruby/test_settracefunc.rb +++ b/test/ruby/test_settracefunc.rb @@ -2140,17 +2140,16 @@ def test_thread_add_trace_func m2t_q.push 1 t.join - assert_equal ["c-return", base_line + 31], events[0] - assert_equal ["line", base_line + 32], events[1] - assert_equal ["line", base_line + 33], events[2] - assert_equal ["call", base_line + -6], events[3] - assert_equal ["return", base_line + -4], events[4] - assert_equal ["line", base_line + 34], events[5] - assert_equal ["line", base_line + 35], events[6] - assert_equal ["c-call", base_line + 35], events[7] # Thread.current - assert_equal ["c-return", base_line + 35], events[8] # Thread.current - assert_equal ["c-call", base_line + 35], events[9] # Thread#set_trace_func - assert_equal nil, events[10] + assert_equal ["line", base_line + 32], events[0] + assert_equal ["line", base_line + 33], events[1] + assert_equal ["call", base_line + -6], events[2] + assert_equal ["return", base_line + -4], events[3] + assert_equal ["line", base_line + 34], events[4] + assert_equal ["line", base_line + 35], events[5] + assert_equal ["c-call", base_line + 35], events[6] # Thread.current + assert_equal ["c-return", base_line + 35], events[7] # Thread.current + assert_equal ["c-call", base_line + 35], events[8] # Thread#set_trace_func + assert_equal nil, events[9] end def test_lineno_in_optimized_insn diff --git a/test/ruby/test_thread.rb b/test/ruby/test_thread.rb index 881c4d102dc4cb..f6156a16fdb949 100644 --- a/test/ruby/test_thread.rb +++ b/test/ruby/test_thread.rb @@ -972,6 +972,8 @@ def test_backtrace end def test_thread_timer_and_interrupt + omit "[Bug #18613]" if /freebsd/ =~ RUBY_PLATFORM + bug5757 = '[ruby-dev:44985]' pid = nil cmd = 'Signal.trap(:INT, "DEFAULT"); pipe=IO.pipe; Thread.start {Thread.pass until Thread.main.stop?; puts; STDOUT.flush}; pipe[0].read' diff --git a/test/ruby/test_thread_queue.rb b/test/ruby/test_thread_queue.rb index ebf7ded3b9beb0..1c852474b4277f 100644 --- a/test/ruby/test_thread_queue.rb +++ b/test/ruby/test_thread_queue.rb @@ -111,6 +111,23 @@ def test_queue_pop_interrupt assert_equal(0, q.num_waiting) end + def test_queue_pop_timeout + q = Thread::Queue.new + q << 1 + assert_equal 1, q.pop(timeout: 1) + + t1 = Thread.new { q.pop(timeout: 1) } + assert_equal t1, t1.join(2) + assert_nil t1.value + + t2 = Thread.new { q.pop(timeout: 0.1) } + assert_equal t2, t2.join(1) + assert_nil t2.value + ensure + t1&.kill&.join + t2&.kill&.join + end + def test_queue_pop_non_block q = Thread::Queue.new assert_raise_with_message(ThreadError, /empty/) do @@ -126,6 +143,24 @@ def test_sized_queue_pop_interrupt assert_equal(0, q.num_waiting) end + def test_sized_queue_pop_timeout + q = Thread::SizedQueue.new(1) + + q << 1 + assert_equal 1, q.pop(timeout: 1) + + t1 = Thread.new { q.pop(timeout: 1) } + assert_equal t1, t1.join(2) + assert_nil t1.value + + t2 = Thread.new { q.pop(timeout: 0.1) } + assert_equal t2, t2.join(1) + assert_nil t2.value + ensure + t1&.kill&.join + t2&.kill&.join + end + def test_sized_queue_pop_non_block q = Thread::SizedQueue.new(1) assert_raise_with_message(ThreadError, /empty/) do diff --git a/test/ruby/test_yjit.rb b/test/ruby/test_yjit.rb index f8fc4f21eff2c7..37e72dcafac3b5 100644 --- a/test/ruby/test_yjit.rb +++ b/test/ruby/test_yjit.rb @@ -513,6 +513,22 @@ def foo &blk RUBY end + def test_getblockparamproxy_with_no_block + # Currently side exits on the send + assert_compiles(<<~'RUBY', insns: [:getblockparamproxy], exits: { send: 2 }) + def bar + end + + def foo &blk + bar(&blk) + bar(&blk) + end + + foo + foo + RUBY + end + def test_send_splat assert_compiles(<<~'RUBY', result: "3#1,2,3/P", exits: {}) def internal_method(*args) diff --git a/test/rubygems/helper.rb b/test/rubygems/helper.rb index dab3cd4d4c4c0d..46eefbb48e4ce0 100644 --- a/test/rubygems/helper.rb +++ b/test/rubygems/helper.rb @@ -270,7 +270,7 @@ def parse_make_command_line_targets(line) end def assert_contains_make_command(target, output, msg = nil) - if output.match(/\n/) + if output.include?("\n") msg = build_message(msg, "Expected output containing make command \"%s\", but was \n\nBEGIN_OF_OUTPUT\n%sEND_OF_OUTPUT" % [ ("%s %s" % [make_command, target]).rstrip, diff --git a/test/rubygems/test_bundled_ca.rb b/test/rubygems/test_bundled_ca.rb index b061666c76981f..3d7f616519f23e 100644 --- a/test/rubygems/test_bundled_ca.rb +++ b/test/rubygems/test_bundled_ca.rb @@ -36,7 +36,7 @@ def assert_https(host) pend "#{host} seems offline, I can't tell whether ssl would work." rescue OpenSSL::SSL::SSLError => e # Only fail for certificate verification errors - if e.message =~ /certificate verify failed/ + if e.message.include?("certificate verify failed") flunk "#{host} is not verifiable using the included certificates. Error was: #{e.message}" end raise diff --git a/test/rubygems/test_gem_bundler_version_finder.rb b/test/rubygems/test_gem_bundler_version_finder.rb index 0e21e460f69b88..60e2b65047cacb 100644 --- a/test/rubygems/test_gem_bundler_version_finder.rb +++ b/test/rubygems/test_gem_bundler_version_finder.rb @@ -78,7 +78,7 @@ def test_bundler_version def test_deleted_directory pend "Cannot perform this test on windows" if win_platform? - pend "Cannot perform this test on Solaris" if /solaris/ =~ RUBY_PLATFORM + pend "Cannot perform this test on Solaris" if RUBY_PLATFORM.include?("solaris") require "tmpdir" orig_dir = Dir.pwd diff --git a/test/rubygems/test_gem_ext_builder.rb b/test/rubygems/test_gem_ext_builder.rb index 6adfd425506d5b..34d89035952ea6 100644 --- a/test/rubygems/test_gem_ext_builder.rb +++ b/test/rubygems/test_gem_ext_builder.rb @@ -106,7 +106,7 @@ def test_custom_make_with_options end def test_build_extensions - pend if /mswin/ =~ RUBY_PLATFORM && ENV.key?("GITHUB_ACTIONS") # not working from the beginning + pend if RUBY_PLATFORM.include?("mswin") && ENV.key?("GITHUB_ACTIONS") # not working from the beginning @spec.extensions << "ext/extconf.rb" ext_dir = File.join @spec.gem_dir, "ext" @@ -142,7 +142,7 @@ def test_build_extensions end def test_build_extensions_with_gemhome_with_space - pend if /mswin/ =~ RUBY_PLATFORM && ENV.key?("GITHUB_ACTIONS") # not working from the beginning + pend if RUBY_PLATFORM.include?("mswin") && ENV.key?("GITHUB_ACTIONS") # not working from the beginning new_gemhome = File.join @tempdir, "gem home" File.rename(@gemhome, new_gemhome) @gemhome = new_gemhome @@ -163,7 +163,7 @@ def Gem.install_extension_in_lib false end end - pend if /mswin/ =~ RUBY_PLATFORM && ENV.key?("GITHUB_ACTIONS") # not working from the beginning + pend if RUBY_PLATFORM.include?("mswin") && ENV.key?("GITHUB_ACTIONS") # not working from the beginning @spec.extensions << "ext/extconf.rb" diff --git a/test/rubygems/test_gem_ext_cargo_builder.rb b/test/rubygems/test_gem_ext_cargo_builder.rb index 5a940b07a82bcb..c6bbab2cb313f6 100644 --- a/test/rubygems/test_gem_ext_cargo_builder.rb +++ b/test/rubygems/test_gem_ext_cargo_builder.rb @@ -164,7 +164,7 @@ def test_custom_name def skip_unsupported_platforms! pend "jruby not supported" if java_platform? pend "truffleruby not supported (yet)" if RUBY_ENGINE == "truffleruby" - pend "mswin not supported (yet)" if /mswin/ =~ RUBY_PLATFORM && ENV.key?("GITHUB_ACTIONS") + pend "mswin not supported (yet)" if RUBY_PLATFORM.include?("mswin") && ENV.key?("GITHUB_ACTIONS") system(@rust_envs, "cargo", "-V", out: IO::NULL, err: [:child, :out]) pend "cargo not present" unless $?.success? pend "ruby.h is not provided by ruby repo" if ruby_repo? diff --git a/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.lock b/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.lock index 498ee26c7e7139..86221bf249e295 100644 --- a/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.lock +++ b/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.lock @@ -160,9 +160,9 @@ dependencies = [ [[package]] name = "rb-sys" -version = "0.9.26" +version = "0.9.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723f7560e878bec9d1d49538a17fb6a4e3a04688c1dc6f14eef17918634a54e4" +checksum = "8d7df1d7911fef801edda0b789cca202f3486dff5073eb13dbb85b4715e6f94a" dependencies = [ "bindgen", "linkify", @@ -171,9 +171,9 @@ dependencies = [ [[package]] name = "rb-sys-build" -version = "0.9.26" +version = "0.9.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ccd93f0d9767385cd7a23076c47e3dca4c86144e510ea4c61d04dbce0cbac7e" +checksum = "c6fa9b908035cb531820f8f3977c538c318308cfaa77da1c6b436577c06db230" dependencies = [ "regex", "shell-words", diff --git a/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.toml b/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.toml index b144f930e58c2b..ae32c194b2959f 100644 --- a/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.toml +++ b/test/rubygems/test_gem_ext_cargo_builder/custom_name/Cargo.toml @@ -7,4 +7,4 @@ edition = "2021" crate-type = ["cdylib"] [dependencies] -rb-sys = { version = "0.9.26", features = ["gem"] } +rb-sys = { version = "0.9.28", features = ["gem"] } diff --git a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock index 497686123119b1..0a95dceca232fc 100644 --- a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock +++ b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.lock @@ -98,9 +98,9 @@ dependencies = [ [[package]] name = "linkify" -version = "0.8.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d9967eb7d0bc31c39c6f52e8fce42991c0cd1f7a2078326f0b7a399a584c8d" +checksum = "96dd5884008358112bc66093362197c7248ece00d46624e2cf71e50029f8cff5" dependencies = [ "memchr", ] @@ -153,9 +153,9 @@ dependencies = [ [[package]] name = "rb-sys" -version = "0.9.20" +version = "0.9.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfe4bf82794b8d3c995847a710da279afcd3bee40b993cd3296af259e5933c4" +checksum = "8d7df1d7911fef801edda0b789cca202f3486dff5073eb13dbb85b4715e6f94a" dependencies = [ "bindgen", "linkify", @@ -164,9 +164,9 @@ dependencies = [ [[package]] name = "rb-sys-build" -version = "0.9.20" +version = "0.9.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb614fa1ac5a7a96685537f123201b727dfa39e7e54e46c1027b3477266be93d" +checksum = "c6fa9b908035cb531820f8f3977c538c318308cfaa77da1c6b436577c06db230" dependencies = [ "regex", "shell-words", diff --git a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml index 357e5f60e405f4..7cced882e98132 100644 --- a/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml +++ b/test/rubygems/test_gem_ext_cargo_builder/rust_ruby_example/Cargo.toml @@ -7,4 +7,4 @@ edition = "2021" crate-type = ["cdylib"] [dependencies] -rb-sys = { version = "0.9.20", features = ["gem"] } +rb-sys = { version = "0.9.28", features = ["gem"] } diff --git a/test/rubygems/test_gem_installer.rb b/test/rubygems/test_gem_installer.rb index 46003175784c16..55f0a074b8776b 100644 --- a/test/rubygems/test_gem_installer.rb +++ b/test/rubygems/test_gem_installer.rb @@ -756,7 +756,10 @@ def test_generate_bin_with_dangling_symlink end end - assert_match %r{bin/ascii_binder` is dangling symlink pointing to `bin/asciibinder`}, @ui.error + errors = @ui.error.split("\n") + assert_equal "WARNING: ascii_binder-0.1.10.1 ships with a dangling symlink named bin/ascii_binder pointing to missing bin/asciibinder file. Ignoring", errors.shift + assert_empty errors + assert_empty @ui.output end @@ -1490,7 +1493,7 @@ def test_find_lib_file_after_install def test_install_extension_and_script pend "Makefile creation crashes on jruby" if Gem.java_platform? - pend if /mswin/ =~ RUBY_PLATFORM && ENV.key?("GITHUB_ACTIONS") # not working from the beginning + pend if RUBY_PLATFORM.include?("mswin") && ENV.key?("GITHUB_ACTIONS") # not working from the beginning @spec = setup_base_spec @spec.extensions << "extconf.rb" diff --git a/test/rubygems/test_gem_package.rb b/test/rubygems/test_gem_package.rb index 9e18dacba1a324..9295f42dba0140 100644 --- a/test/rubygems/test_gem_package.rb +++ b/test/rubygems/test_gem_package.rb @@ -529,6 +529,7 @@ def test_extract_tar_gz_absolute def test_extract_tar_gz_symlink_relative_path package = Gem::Package.new @gem + package.verify tgz_io = util_tar_gz do |tar| tar.add_file "relative.rb", 0644 do |io| @@ -557,6 +558,27 @@ def test_extract_tar_gz_symlink_relative_path File.read(extracted) end + def test_extract_tar_gz_symlink_broken_relative_path + package = Gem::Package.new @gem + package.verify + + tgz_io = util_tar_gz do |tar| + tar.mkdir "lib", 0755 + tar.add_symlink "lib/foo.rb", "../broken.rb", 0644 + end + + ui = Gem::MockGemUi.new + + use_ui ui do + package.extract_tar_gz tgz_io, @destination + end + + assert_equal "WARNING: a-2 ships with a dangling symlink named lib/foo.rb pointing to missing ../broken.rb file. Ignoring\n", ui.error + + extracted = File.join @destination, "lib/foo.rb" + assert_path_not_exist extracted + end + def test_extract_symlink_parent package = Gem::Package.new @gem diff --git a/test/rubygems/test_gem_requirement.rb b/test/rubygems/test_gem_requirement.rb index 37137dbdad80d3..29bb264454f64f 100644 --- a/test/rubygems/test_gem_requirement.rb +++ b/test/rubygems/test_gem_requirement.rb @@ -83,7 +83,7 @@ def test_parse Gem::Requirement.parse(Gem::Version.new("2")) end - if RUBY_VERSION >= "2.5" && !(Gem.java_platform? && ENV["JRUBY_OPTS"] =~ /--debug/) + if RUBY_VERSION >= "2.5" && !(Gem.java_platform? && ENV["JRUBY_OPTS"].to_s.include?("--debug")) def test_parse_deduplication assert_same "~>", Gem::Requirement.parse("~> 1").first end @@ -129,7 +129,9 @@ def test_satisfied_by_eh_bang_equal assert_satisfied_by "1.3", r assert_raise ArgumentError do - assert_satisfied_by nil, r + Gem::Deprecate.skip_during do + assert_satisfied_by nil, r + end end end @@ -141,7 +143,9 @@ def test_satisfied_by_eh_blank refute_satisfied_by "1.3", r assert_raise ArgumentError do - assert_satisfied_by nil, r + Gem::Deprecate.skip_during do + assert_satisfied_by nil, r + end end end @@ -153,7 +157,9 @@ def test_satisfied_by_eh_equal refute_satisfied_by "1.3", r assert_raise ArgumentError do - assert_satisfied_by nil, r + Gem::Deprecate.skip_during do + assert_satisfied_by nil, r + end end end diff --git a/test/rubygems/test_gem_resolver_git_specification.rb b/test/rubygems/test_gem_resolver_git_specification.rb index fef071aa7632f5..454fd9c6e49535 100644 --- a/test/rubygems/test_gem_resolver_git_specification.rb +++ b/test/rubygems/test_gem_resolver_git_specification.rb @@ -63,7 +63,7 @@ def test_install def test_install_extension pend if Gem.java_platform? - pend if /mswin/ =~ RUBY_PLATFORM && ENV.key?("GITHUB_ACTIONS") # not working from the beginning + pend if RUBY_PLATFORM.include?("mswin") && ENV.key?("GITHUB_ACTIONS") # not working from the beginning name, _, repository, = git_gem "a", 1 do |s| s.extensions << "ext/extconf.rb" end diff --git a/test/rubygems/test_gem_resolver_index_specification.rb b/test/rubygems/test_gem_resolver_index_specification.rb index 339445cb44583f..b479757bd557fe 100644 --- a/test/rubygems/test_gem_resolver_index_specification.rb +++ b/test/rubygems/test_gem_resolver_index_specification.rb @@ -26,7 +26,7 @@ def test_initialize_platform spec = Gem::Resolver::IndexSpecification.new( set, "rails", version, source, Gem::Platform.local) - assert_equal Gem::Platform.local.to_s, spec.platform + assert_equal Gem::Platform.local, spec.platform end def test_install diff --git a/test/rubygems/test_gem_resolver_installer_set.rb b/test/rubygems/test_gem_resolver_installer_set.rb index 8d84c28172a7fe..ffa6b13ea4d599 100644 --- a/test/rubygems/test_gem_resolver_installer_set.rb +++ b/test/rubygems/test_gem_resolver_installer_set.rb @@ -51,6 +51,19 @@ def test_add_always_install_platform assert_equal %w[a-1], set.always_install.map {|s| s.full_name } end + def test_add_always_install_index_spec_platform + _, a_1_local_gem = util_gem "a", 1 do |s| + s.platform = Gem::Platform.local + end + + FileUtils.mv a_1_local_gem, @tempdir + + set = Gem::Resolver::InstallerSet.new :both + set.add_always_install dep("a") + + assert_equal [Gem::Platform.local], set.always_install.map {|s| s.platform } + end + def test_add_always_install_prerelease spec_fetcher do |fetcher| fetcher.gem "a", 1 diff --git a/test/rubygems/test_gem_security_trust_dir.rb b/test/rubygems/test_gem_security_trust_dir.rb index 8c59286679e45c..b74e21fb5cfc53 100644 --- a/test/rubygems/test_gem_security_trust_dir.rb +++ b/test/rubygems/test_gem_security_trust_dir.rb @@ -70,7 +70,7 @@ def test_verify assert_path_exist @dest_dir mask = 040700 & (~File.umask) - mask |= 0200000 if /aix/ =~ RUBY_PLATFORM + mask |= 0200000 if RUBY_PLATFORM.include?("aix") assert_equal mask, File.stat(@dest_dir).mode unless win_platform? end @@ -91,7 +91,7 @@ def test_verify_wrong_permissions @trust_dir.verify mask = 040700 & (~File.umask) - mask |= 0200000 if /aix/ =~ RUBY_PLATFORM + mask |= 0200000 if RUBY_PLATFORM.include?("aix") assert_equal mask, File.stat(@dest_dir).mode unless win_platform? end diff --git a/test/rubygems/test_gem_specification.rb b/test/rubygems/test_gem_specification.rb index 6117e81a81a42f..cf0dba4331fc3c 100644 --- a/test/rubygems/test_gem_specification.rb +++ b/test/rubygems/test_gem_specification.rb @@ -1220,6 +1220,15 @@ def test_initialize_prerelease_version_before_name assert_equal "1.0.0.dev", spec.version.to_s end + def test_initialize_nil_version + expected = "nil versions are discouraged and will be deprecated in Rubygems 4\n" + actual_stdout, actual_stderr = capture_output do + Gem::Specification.new.version = nil + end + assert_empty actual_stdout + assert_equal(expected, actual_stderr) + end + def test__dump @a2.platform = Gem::Platform.local @a2.instance_variable_set :@original_platform, "old_platform" diff --git a/test/rubygems/test_gem_version.rb b/test/rubygems/test_gem_version.rb index e907eabb34d801..9237608d4a8ca9 100644 --- a/test/rubygems/test_gem_version.rb +++ b/test/rubygems/test_gem_version.rb @@ -32,8 +32,15 @@ def test_bump_one_level def test_class_create real = Gem::Version.new(1.0) - assert_same real, Gem::Version.create(real) - assert_nil Gem::Version.create(nil) + assert_same real, Gem::Version.create(real) + + expected = "nil versions are discouraged and will be deprecated in Rubygems 4\n" + actual_stdout, actual_stderr = capture_output do + assert_nil Gem::Version.create(nil) + end + assert_empty actual_stdout + assert_equal(expected, actual_stderr) + assert_equal v("5.1"), Gem::Version.create("5.1") ver = "1.1".freeze diff --git a/test/rubygems/test_kernel.rb b/test/rubygems/test_kernel.rb index cced65fa50d89a..091a5419fbb41f 100644 --- a/test/rubygems/test_kernel.rb +++ b/test/rubygems/test_kernel.rb @@ -20,7 +20,7 @@ def teardown def test_gem assert gem("a", "= 1"), "Should load" - assert $:.any? {|p| %r{a-1/lib} =~ p } + assert $:.any? {|p| p.include?("a-1/lib") } end def test_gem_default @@ -50,13 +50,13 @@ def test_gem_re_gem_mismatch def test_gem_redundant assert gem("a", "= 1"), "Should load" refute gem("a", "= 1"), "Should not load" - assert_equal 1, $:.select {|p| %r{a-1/lib} =~ p }.size + assert_equal 1, $:.select {|p| p.include?("a-1/lib") }.size end def test_gem_overlapping assert gem("a", "= 1"), "Should load" refute gem("a", ">= 1"), "Should not load" - assert_equal 1, $:.select {|p| %r{a-1/lib} =~ p }.size + assert_equal 1, $:.select {|p| p.include?("a-1/lib") }.size end def test_gem_prerelease @@ -83,13 +83,13 @@ def test_gem_conflicting assert_match(/activated a-1/, ex.message) assert_equal "a", ex.name - assert $:.any? {|p| %r{a-1/lib} =~ p } - refute $:.any? {|p| %r{a-2/lib} =~ p } + assert $:.any? {|p| p.include?("a-1/lib") } + refute $:.any? {|p| p.include?("a-2/lib") } end def test_gem_not_adding_bin assert gem("a", "= 1"), "Should load" - refute $:.any? {|p| %r{a-1/bin} =~ p } + refute $:.any? {|p| p.include?("a-1/bin") } end def test_gem_failing_inside_require_doesnt_cause_double_exceptions @@ -114,7 +114,7 @@ def test_gem_bundler quick_gem "bundler", "2.a" assert gem("bundler") - assert $:.any? {|p| %r{bundler-1/lib} =~ p } + assert $:.any? {|p| p.include?("bundler-1/lib") } end def test_gem_bundler_inferred_bundler_version @@ -123,7 +123,7 @@ def test_gem_bundler_inferred_bundler_version quick_gem "bundler", "2.a" assert gem("bundler", ">= 0.a") - assert $:.any? {|p| %r{bundler-1/lib} =~ p } + assert $:.any? {|p| p.include?("bundler-1/lib") } end end end diff --git a/thread.c b/thread.c index 87f82d0a0e5251..feb89d435271ae 100644 --- a/thread.c +++ b/thread.c @@ -132,7 +132,7 @@ rb_thread_local_storage(VALUE thread) static int sleep_hrtime(rb_thread_t *, rb_hrtime_t, unsigned int fl); static void sleep_forever(rb_thread_t *th, unsigned int fl); -static void rb_thread_sleep_deadly_allow_spurious_wakeup(VALUE blocker); +static void rb_thread_sleep_deadly_allow_spurious_wakeup(VALUE blocker, VALUE timeout, rb_hrtime_t end); static int rb_threadptr_dead(rb_thread_t *th); static void rb_check_deadlock(rb_ractor_t *r); static int rb_threadptr_pending_interrupt_empty_p(const rb_thread_t *th); @@ -843,7 +843,7 @@ thread_create_core(VALUE thval, struct thread_create_params *params) th->priority = current_th->priority; th->thgroup = current_th->thgroup; - th->pending_interrupt_queue = rb_ary_tmp_new(0); + th->pending_interrupt_queue = rb_ary_hidden_new(0); th->pending_interrupt_queue_checked = 0; th->pending_interrupt_mask_stack = rb_ary_dup(current_th->pending_interrupt_mask_stack); RBASIC_CLEAR_CLASS(th->pending_interrupt_mask_stack); @@ -1328,6 +1328,28 @@ sleep_hrtime(rb_thread_t *th, rb_hrtime_t rel, unsigned int fl) return woke; } +static int +sleep_hrtime_until(rb_thread_t *th, rb_hrtime_t end, unsigned int fl) +{ + enum rb_thread_status prev_status = th->status; + int woke; + rb_hrtime_t rel = rb_hrtime_sub(end, rb_hrtime_now()); + + th->status = THREAD_STOPPED; + RUBY_VM_CHECK_INTS_BLOCKING(th->ec); + while (th->status == THREAD_STOPPED) { + native_sleep(th, &rel); + woke = vm_check_ints_blocking(th->ec); + if (woke && !(fl & SLEEP_SPURIOUS_CHECK)) + break; + if (hrtime_update_expire(&rel, end)) + break; + woke = 1; + } + th->status = prev_status; + return woke; +} + void rb_thread_sleep_forever(void) { @@ -1355,15 +1377,20 @@ rb_thread_sleep_interruptible(void) } static void -rb_thread_sleep_deadly_allow_spurious_wakeup(VALUE blocker) +rb_thread_sleep_deadly_allow_spurious_wakeup(VALUE blocker, VALUE timeout, rb_hrtime_t end) { VALUE scheduler = rb_fiber_scheduler_current(); if (scheduler != Qnil) { - rb_fiber_scheduler_block(scheduler, blocker, Qnil); + rb_fiber_scheduler_block(scheduler, blocker, timeout); } else { RUBY_DEBUG_LOG("%s", ""); - sleep_forever(GET_THREAD(), SLEEP_DEADLOCKABLE); + if (end) { + sleep_hrtime_until(GET_THREAD(), end, SLEEP_SPURIOUS_CHECK); + } + else { + sleep_forever(GET_THREAD(), SLEEP_DEADLOCKABLE); + } } } @@ -5352,9 +5379,9 @@ Init_Thread(void) struct rb_thread_sched *sched = TH_SCHED(th); thread_sched_to_running(sched, th); - th->pending_interrupt_queue = rb_ary_tmp_new(0); + th->pending_interrupt_queue = rb_ary_hidden_new(0); th->pending_interrupt_queue_checked = 0; - th->pending_interrupt_mask_stack = rb_ary_tmp_new(0); + th->pending_interrupt_mask_stack = rb_ary_hidden_new(0); } } @@ -5651,17 +5678,17 @@ rb_reset_coverages(void) VALUE rb_default_coverage(int n) { - VALUE coverage = rb_ary_tmp_new_fill(3); + VALUE coverage = rb_ary_hidden_new_fill(3); VALUE lines = Qfalse, branches = Qfalse; int mode = GET_VM()->coverage_mode; if (mode & COVERAGE_TARGET_LINES) { - lines = n > 0 ? rb_ary_tmp_new_fill(n) : rb_ary_tmp_new(0); + lines = n > 0 ? rb_ary_hidden_new_fill(n) : rb_ary_hidden_new(0); } RARRAY_ASET(coverage, COVERAGE_INDEX_LINES, lines); if (mode & COVERAGE_TARGET_BRANCHES) { - branches = rb_ary_tmp_new_fill(2); + branches = rb_ary_hidden_new_fill(2); /* internal data structures for branch coverage: * * { branch base node => @@ -5687,7 +5714,7 @@ rb_default_coverage(int n) rb_obj_hide(structure); RARRAY_ASET(branches, 0, structure); /* branch execution counters */ - RARRAY_ASET(branches, 1, rb_ary_tmp_new(0)); + RARRAY_ASET(branches, 1, rb_ary_hidden_new(0)); } RARRAY_ASET(coverage, COVERAGE_INDEX_BRANCHES, branches); diff --git a/thread_pthread.c b/thread_pthread.c index e748797fe70e9a..c29c7e195806e7 100644 --- a/thread_pthread.c +++ b/thread_pthread.c @@ -146,7 +146,8 @@ rb_internal_thread_remove_event_hook(rb_internal_thread_event_hook_t * hook) if (rb_internal_thread_event_hooks == hook) { ATOMIC_PTR_EXCHANGE(rb_internal_thread_event_hooks, hook->next); success = TRUE; - } else { + } + else { rb_internal_thread_event_hook_t *h = rb_internal_thread_event_hooks; do { diff --git a/thread_sync.c b/thread_sync.c index 09f824c622504a..0359ac2214d808 100644 --- a/thread_sync.c +++ b/thread_sync.c @@ -1,5 +1,6 @@ /* included by thread.c */ #include "ccan/list/list.h" +#include "builtin.h" static VALUE rb_cMutex, rb_cQueue, rb_cSizedQueue, rb_cConditionVariable; static VALUE rb_eClosedQueueError; @@ -19,6 +20,12 @@ struct sync_waiter { struct ccan_list_node node; }; +struct queue_sleep_arg { + VALUE self; + VALUE timeout; + rb_hrtime_t end; +}; + #define MUTEX_ALLOW_TRAP FL_USER1 static void @@ -514,7 +521,7 @@ rb_mutex_abandon_all(rb_mutex_t *mutexes) static VALUE rb_mutex_sleep_forever(VALUE self) { - rb_thread_sleep_deadly_allow_spurious_wakeup(self); + rb_thread_sleep_deadly_allow_spurious_wakeup(self, Qnil, 0); return Qnil; } @@ -706,6 +713,21 @@ queue_ptr(VALUE obj) #define QUEUE_CLOSED FL_USER5 +static rb_hrtime_t +queue_timeout2hrtime(VALUE timeout) { + if (NIL_P(timeout)) { + return (rb_hrtime_t)0; + } + rb_hrtime_t rel = 0; + if (FIXNUM_P(timeout)) { + rel = rb_sec2hrtime(NUM2TIMET(timeout)); + } + else { + double2hrtime(&rel, rb_num2dbl(timeout)); + } + return rb_hrtime_add(rel, rb_hrtime_now()); +} + static void szqueue_mark(void *ptr) { @@ -754,7 +776,7 @@ szqueue_ptr(VALUE obj) static VALUE ary_buf_new(void) { - return rb_ary_tmp_new(1); + return rb_ary_hidden_new(1); } static VALUE @@ -964,9 +986,10 @@ rb_queue_push(VALUE self, VALUE obj) } static VALUE -queue_sleep(VALUE self) +queue_sleep(VALUE _args) { - rb_thread_sleep_deadly_allow_spurious_wakeup(self); + struct queue_sleep_arg *args = (struct queue_sleep_arg *)_args; + rb_thread_sleep_deadly_allow_spurious_wakeup(args->self, args->timeout, args->end); return Qnil; } @@ -1001,9 +1024,10 @@ szqueue_sleep_done(VALUE p) } static VALUE -queue_do_pop(VALUE self, struct rb_queue *q, int should_block) +queue_do_pop(VALUE self, struct rb_queue *q, int should_block, VALUE timeout) { check_array(self, q->que); + rb_hrtime_t end = queue_timeout2hrtime(timeout); while (RARRAY_LEN(q->que) == 0) { if (!should_block) { @@ -1028,43 +1052,25 @@ queue_do_pop(VALUE self, struct rb_queue *q, int should_block) ccan_list_add_tail(waitq, &queue_waiter.w.node); queue_waiter.as.q->num_waiting++; - rb_ensure(queue_sleep, self, queue_sleep_done, (VALUE)&queue_waiter); + struct queue_sleep_arg queue_sleep_arg = { + .self = self, + .timeout = timeout, + .end = end + }; + + rb_ensure(queue_sleep, (VALUE)&queue_sleep_arg, queue_sleep_done, (VALUE)&queue_waiter); + if (!NIL_P(timeout) && (rb_hrtime_now() >= end)) + break; } } return rb_ary_shift(q->que); } -static int -queue_pop_should_block(int argc, const VALUE *argv) -{ - int should_block = 1; - rb_check_arity(argc, 0, 1); - if (argc > 0) { - should_block = !RTEST(argv[0]); - } - return should_block; -} - -/* - * Document-method: Thread::Queue#pop - * call-seq: - * pop(non_block=false) - * deq(non_block=false) - * shift(non_block=false) - * - * Retrieves data from the queue. - * - * If the queue is empty, the calling thread is suspended until data is pushed - * onto the queue. If +non_block+ is true, the thread isn't suspended, and - * +ThreadError+ is raised. - */ - static VALUE -rb_queue_pop(int argc, VALUE *argv, VALUE self) +rb_queue_pop(rb_execution_context_t *ec, VALUE self, VALUE non_block, VALUE timeout) { - int should_block = queue_pop_should_block(argc, argv); - return queue_do_pop(self, queue_ptr(self), should_block); + return queue_do_pop(self, queue_ptr(self), !RTEST(non_block), timeout); } /* @@ -1271,7 +1277,13 @@ rb_szqueue_push(int argc, VALUE *argv, VALUE self) ccan_list_add_tail(pushq, &queue_waiter.w.node); sq->num_waiting_push++; - rb_ensure(queue_sleep, self, szqueue_sleep_done, (VALUE)&queue_waiter); + struct queue_sleep_arg queue_sleep_arg = { + .self = self, + .timeout = Qnil, + .end = 0 + }; + + rb_ensure(queue_sleep, (VALUE)&queue_sleep_arg, szqueue_sleep_done, (VALUE)&queue_waiter); } } @@ -1283,10 +1295,10 @@ rb_szqueue_push(int argc, VALUE *argv, VALUE self) } static VALUE -szqueue_do_pop(VALUE self, int should_block) +szqueue_do_pop(VALUE self, int should_block, VALUE timeout) { struct rb_szqueue *sq = szqueue_ptr(self); - VALUE retval = queue_do_pop(self, &sq->q, should_block); + VALUE retval = queue_do_pop(self, &sq->q, should_block, timeout); if (queue_length(self, &sq->q) < sq->max) { wakeup_one(szqueue_pushq(sq)); @@ -1294,26 +1306,10 @@ szqueue_do_pop(VALUE self, int should_block) return retval; } - -/* - * Document-method: Thread::SizedQueue#pop - * call-seq: - * pop(non_block=false) - * deq(non_block=false) - * shift(non_block=false) - * - * Retrieves data from the queue. - * - * If the queue is empty, the calling thread is suspended until data is pushed - * onto the queue. If +non_block+ is true, the thread isn't suspended, and - * +ThreadError+ is raised. - */ - static VALUE -rb_szqueue_pop(int argc, VALUE *argv, VALUE self) +rb_szqueue_pop(rb_execution_context_t *ec, VALUE self, VALUE non_block, VALUE timeout) { - int should_block = queue_pop_should_block(argc, argv); - return szqueue_do_pop(self, should_block); + return szqueue_do_pop(self, !RTEST(non_block), timeout); } /* @@ -1597,7 +1593,6 @@ Init_thread_sync(void) rb_define_method(rb_cQueue, "close", rb_queue_close, 0); rb_define_method(rb_cQueue, "closed?", rb_queue_closed_p, 0); rb_define_method(rb_cQueue, "push", rb_queue_push, 1); - rb_define_method(rb_cQueue, "pop", rb_queue_pop, -1); rb_define_method(rb_cQueue, "empty?", rb_queue_empty_p, 0); rb_define_method(rb_cQueue, "clear", rb_queue_clear, 0); rb_define_method(rb_cQueue, "length", rb_queue_length, 0); @@ -1605,8 +1600,6 @@ Init_thread_sync(void) rb_define_alias(rb_cQueue, "enq", "push"); rb_define_alias(rb_cQueue, "<<", "push"); - rb_define_alias(rb_cQueue, "deq", "pop"); - rb_define_alias(rb_cQueue, "shift", "pop"); rb_define_alias(rb_cQueue, "size", "length"); DEFINE_CLASS(SizedQueue, Queue); @@ -1617,16 +1610,12 @@ Init_thread_sync(void) rb_define_method(rb_cSizedQueue, "max", rb_szqueue_max_get, 0); rb_define_method(rb_cSizedQueue, "max=", rb_szqueue_max_set, 1); rb_define_method(rb_cSizedQueue, "push", rb_szqueue_push, -1); - rb_define_method(rb_cSizedQueue, "pop", rb_szqueue_pop, -1); rb_define_method(rb_cSizedQueue, "empty?", rb_szqueue_empty_p, 0); rb_define_method(rb_cSizedQueue, "clear", rb_szqueue_clear, 0); rb_define_method(rb_cSizedQueue, "length", rb_szqueue_length, 0); rb_define_method(rb_cSizedQueue, "num_waiting", rb_szqueue_num_waiting, 0); - rb_define_alias(rb_cSizedQueue, "enq", "push"); rb_define_alias(rb_cSizedQueue, "<<", "push"); - rb_define_alias(rb_cSizedQueue, "deq", "pop"); - rb_define_alias(rb_cSizedQueue, "shift", "pop"); rb_define_alias(rb_cSizedQueue, "size", "length"); /* CVar */ @@ -1644,3 +1633,5 @@ Init_thread_sync(void) rb_provide("thread.rb"); } + +#include "thread_sync.rbinc" diff --git a/thread_sync.rb b/thread_sync.rb new file mode 100644 index 00000000000000..d567ca51af1047 --- /dev/null +++ b/thread_sync.rb @@ -0,0 +1,45 @@ +class Thread + class Queue + # call-seq: + # pop(non_block=false, timeout: nil) + # + # Retrieves data from the queue. + # + # If the queue is empty, the calling thread is suspended until data is pushed + # onto the queue. If +non_block+ is true, the thread isn't suspended, and + # +ThreadError+ is raised. + # + # If +timeout+ seconds have passed and no data is available +nil+ is + # returned. + def pop(non_block = false, timeout: nil) + if non_block && timeout + raise ArgumentError, "can't set a timeout if non_block is enabled" + end + Primitive.rb_queue_pop(non_block, timeout) + end + alias_method :deq, :pop + alias_method :shift, :pop + end + + class SizedQueue + # call-seq: + # pop(non_block=false, timeout: nil) + # + # Retrieves data from the queue. + # + # If the queue is empty, the calling thread is suspended until data is + # pushed onto the queue. If +non_block+ is true, the thread isn't + # suspended, and +ThreadError+ is raised. + # + # If +timeout+ seconds have passed and no data is available +nil+ is + # returned. + def pop(non_block = false, timeout: nil) + if non_block && timeout + raise ArgumentError, "can't set a timeout if non_block is enabled" + end + Primitive.rb_szqueue_pop(non_block, timeout) + end + alias_method :deq, :pop + alias_method :shift, :pop + end +end diff --git a/tool/fake.rb b/tool/fake.rb index 88709b2f23ee61..91dfb041c4e30d 100644 --- a/tool/fake.rb +++ b/tool/fake.rb @@ -45,6 +45,7 @@ class File $extout_prefix = '$(extout)$(target_prefix)/' config = RbConfig::CONFIG mkconfig = RbConfig::MAKEFILE_CONFIG + $builtruby ||= File.join(builddir, config['RUBY_INSTALL_NAME'] + config['EXEEXT']) RbConfig.fire_update!("builddir", builddir) RbConfig.fire_update!("buildlibdir", builddir) RbConfig.fire_update!("libdir", builddir) diff --git a/tool/fetch-bundled_gems.rb b/tool/fetch-bundled_gems.rb index 90c5fbff37d228..8d04892b702463 100755 --- a/tool/fetch-bundled_gems.rb +++ b/tool/fetch-bundled_gems.rb @@ -27,5 +27,5 @@ checkout = %w"git -c advice.detachedHead=false checkout" puts "checking out #{c} (v=#{v}, r=#{r}) ..." unless system(*checkout, c, "--", chdir: n) - abort + abort if r or !system(*checkout, v, "--", chdir: n) end diff --git a/tool/sync_default_gems.rb b/tool/sync_default_gems.rb index e5821898afa766..e3b940e2d5a20c 100755 --- a/tool/sync_default_gems.rb +++ b/tool/sync_default_gems.rb @@ -128,6 +128,7 @@ def sync_default_gems(gem) when "rdoc" rm_rf(%w[lib/rdoc lib/rdoc.rb test/rdoc libexec/rdoc libexec/ri]) cp_r(Dir.glob("#{upstream}/lib/rdoc*"), "lib") + cp_r("#{upstream}/doc/rdoc", "doc") cp_r("#{upstream}/test/rdoc", "test") cp_r("#{upstream}/rdoc.gemspec", "lib/rdoc") cp_r("#{upstream}/Gemfile", "lib/rdoc") @@ -183,7 +184,7 @@ def sync_default_gems(gem) rm_rf(%w[ext/psych/lib/psych.{bundle,so} ext/psych/lib/2.*]) rm_rf(["ext/psych/yaml/LICENSE"]) cp_r("#{upstream}/psych.gemspec", "ext/psych") - `git checkout ext/psych/depend` + `git checkout ext/psych/depend ext/psych/.gitignore` when "fiddle" rm_rf(%w[ext/fiddle test/fiddle]) cp_r("#{upstream}/ext/fiddle", "ext") diff --git a/tool/test-bundled-gems.rb b/tool/test-bundled-gems.rb index ac27b9579c5a26..12358b69cc43ea 100644 --- a/tool/test-bundled-gems.rb +++ b/tool/test-bundled-gems.rb @@ -24,7 +24,7 @@ next if ARGV.any? {|pat| !File.fnmatch?(pat, gem)} puts "#{github_actions ? "##[group]" : "\n"}Testing the #{gem} gem" - test_command = "#{ruby} -C #{gem_dir}/src/#{gem} -Ilib #{rake} test" + test_command = "#{ruby} -C #{gem_dir}/src/#{gem} #{rake} test" first_timeout = 600 # 10min toplib = gem diff --git a/version.h b/version.h index 6ef7dc799b57fe..bcd3b29f5095f8 100644 --- a/version.h +++ b/version.h @@ -14,8 +14,8 @@ #define RUBY_PATCHLEVEL -1 #define RUBY_RELEASE_YEAR 2022 -#define RUBY_RELEASE_MONTH 7 -#define RUBY_RELEASE_DAY 26 +#define RUBY_RELEASE_MONTH 8 +#define RUBY_RELEASE_DAY 5 #include "ruby/version.h" #include "ruby/internal/abi.h" diff --git a/vm.c b/vm.c index bb2888ea73adc1..3bba390e7cba18 100644 --- a/vm.c +++ b/vm.c @@ -3932,7 +3932,7 @@ Init_vm_objects(void) vm->defined_module_hash = st_init_numtable(); /* initialize mark object array, hash */ - vm->mark_object_ary = rb_ary_tmp_new(128); + vm->mark_object_ary = rb_ary_hidden_new(128); vm->loading_table = st_init_strtable(); vm->frozen_strings = st_init_table_with_size(&rb_fstring_hash_type, 10000); } diff --git a/vm_args.c b/vm_args.c index 197fdd4b95f951..35adfd94b183ec 100644 --- a/vm_args.c +++ b/vm_args.c @@ -280,7 +280,7 @@ static VALUE make_unknown_kw_hash(const VALUE *passed_keywords, int passed_keyword_len, const VALUE *kw_argv) { int i; - VALUE obj = rb_ary_tmp_new(1); + VALUE obj = rb_ary_hidden_new(1); for (i=0; icfp, *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec); const rb_callable_method_entry_t *cme; + // Skip dummy frame; see `rb_ec_partial_backtrace_object` for details + end_cfp = RUBY_VM_NEXT_CONTROL_FRAME(end_cfp); + for (i=0; i 0) { diff --git a/vm_debug.h b/vm_debug.h index ead1c7c10a8b9d..59561056488001 100644 --- a/vm_debug.h +++ b/vm_debug.h @@ -100,7 +100,7 @@ bool ruby_debug_log_filter(const char *func_name, const char *file_name); } while (0) #define RUBY_DEBUG_LOG2(file, line, ...) do { \ - if (RUBY_DEBUG_LOG_ENABLED(RUBY_FUNCTION_NAME_STRING, __FILE__)) \ + if (RUBY_DEBUG_LOG_ENABLED(RUBY_FUNCTION_NAME_STRING, file)) \ ruby_debug_log(file, line, RUBY_FUNCTION_NAME_STRING, "" __VA_ARGS__); \ } while (0) diff --git a/vm_eval.c b/vm_eval.c index e490e4e32dcf62..c7669cbb858e2a 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -1828,7 +1828,10 @@ VALUE ruby_eval_string_from_file(const char *str, const char *filename) { VALUE file = filename ? rb_str_new_cstr(filename) : 0; - return eval_string_with_cref(rb_vm_top_self(), rb_str_new2(str), NULL, file, 1); + rb_execution_context_t *ec = GET_EC(); + rb_control_frame_t *cfp = ec ? rb_vm_get_ruby_level_next_cfp(ec, ec->cfp) : NULL; + VALUE self = cfp ? cfp->self : rb_vm_top_self(); + return eval_string_with_cref(self, rb_str_new2(str), NULL, file, 1); } VALUE diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 2fb1ecb5f70bf5..2ff48d26626eeb 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -5359,7 +5359,8 @@ vm_opt_ltlt(VALUE recv, VALUE obj) BASIC_OP_UNREDEFINED_P(BOP_LTLT, STRING_REDEFINED_OP_FLAG)) { if (LIKELY(RB_TYPE_P(obj, T_STRING))) { return rb_str_buf_append(recv, obj); - } else { + } + else { return rb_str_concat(recv, obj); } } diff --git a/vm_sync.c b/vm_sync.c index 610bdb7b10d585..b0634955e63103 100644 --- a/vm_sync.c +++ b/vm_sync.c @@ -106,13 +106,15 @@ vm_lock_enter(rb_ractor_t *cr, rb_vm_t *vm, bool locked, bool no_barrier, unsign vm->ractor.sync.lock_rec++; *lev = vm->ractor.sync.lock_rec; - RUBY_DEBUG_LOG2(file, line, "rec:%u owner:%d", vm->ractor.sync.lock_rec, rb_ractor_id(vm->ractor.sync.lock_owner)); + RUBY_DEBUG_LOG2(file, line, "rec:%u owner:%u", vm->ractor.sync.lock_rec, + (unsigned int)rb_ractor_id(vm->ractor.sync.lock_owner)); } static void vm_lock_leave(rb_vm_t *vm, unsigned int *lev APPEND_LOCATION_ARGS) { - RUBY_DEBUG_LOG2(file, line, "rec:%u owner:%d", vm->ractor.sync.lock_rec, rb_ractor_id(vm->ractor.sync.lock_owner)); + RUBY_DEBUG_LOG2(file, line, "rec:%u owner:%u", vm->ractor.sync.lock_rec, + (unsigned int)rb_ractor_id(vm->ractor.sync.lock_owner)); ASSERT_vm_locking(); VM_ASSERT(vm->ractor.sync.lock_rec > 0); diff --git a/yjit.c b/yjit.c index 13c3093764f084..584f909473f126 100644 --- a/yjit.c +++ b/yjit.c @@ -97,7 +97,8 @@ rb_yjit_add_frame(VALUE hash, VALUE frame) if (RTEST(rb_hash_aref(hash, frame_id))) { return; - } else { + } + else { VALUE frame_info = rb_hash_new(); // Full label for the frame VALUE name = rb_profile_frame_full_label(frame); @@ -716,6 +717,17 @@ rb_get_cfp_ep(struct rb_control_frame_struct *cfp) return (VALUE*)cfp->ep; } +const VALUE * +rb_get_cfp_ep_level(struct rb_control_frame_struct *cfp, uint32_t lv) +{ + uint32_t i; + const VALUE *ep = (VALUE*)cfp->ep; + for (i = 0; i < lv; i++) { + ep = VM_ENV_PREV_EP(ep); + } + return ep; +} + VALUE rb_yarv_class_of(VALUE obj) { diff --git a/yjit/Cargo.toml b/yjit/Cargo.toml index a5208049cbc84a..4641de205f1d32 100644 --- a/yjit/Cargo.toml +++ b/yjit/Cargo.toml @@ -30,6 +30,12 @@ debug = true debug-assertions = true overflow-checks = true +[profile.stats] +inherits = "release" + +[profile.dev_nodebug] +inherits = "release" + [profile.release] # NOTE: --enable-yjit builds use `rustc` without going through Cargo. You # might want to update the `rustc` invocation if you change this profile. diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index c14b147af9c004..3551058334b63e 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -180,6 +180,15 @@ fn jit_peek_at_local(jit: &JITState, n: i32) -> VALUE { } } +fn jit_peek_at_block_handler(jit: &JITState, level: u32) -> VALUE { + assert!(jit_at_current_insn(jit)); + + unsafe { + let ep = get_cfp_ep_level(get_ec_cfp(jit.ec.unwrap()), level); + *ep.offset(VM_ENV_DATA_INDEX_SPECVAL as isize) + } +} + // Add a comment at the current position in the code block fn add_comment(cb: &mut CodeBlock, comment_str: &str) { if cfg!(feature = "asm_comments") { @@ -1319,6 +1328,31 @@ fn guard_object_is_array( jne_ptr(cb, side_exit); } +fn guard_object_is_string( + cb: &mut CodeBlock, + object_reg: X86Opnd, + flags_reg: X86Opnd, + side_exit: CodePtr, +) { + add_comment(cb, "guard object is string"); + + // Pull out the type mask + mov( + cb, + flags_reg, + mem_opnd( + 8 * SIZEOF_VALUE as u8, + object_reg, + RUBY_OFFSET_RBASIC_FLAGS, + ), + ); + and(cb, flags_reg, uimm_opnd(RUBY_T_MASK as u64)); + + // Compare the result with T_STRING + cmp(cb, flags_reg, uimm_opnd(RUBY_T_STRING as u64)); + jne_ptr(cb, side_exit); +} + // push enough nils onto the stack to fill out an array fn gen_expandarray( jit: &mut JITState, @@ -2190,22 +2224,16 @@ fn gen_checktype( let val = ctx.stack_pop(1); // Check if we know from type information - match (type_val, val_type) { - (RUBY_T_STRING, Type::TString) - | (RUBY_T_STRING, Type::CString) - | (RUBY_T_ARRAY, Type::Array) - | (RUBY_T_HASH, Type::Hash) => { - // guaranteed type match - let stack_ret = ctx.stack_push(Type::True); - asm.mov(stack_ret, Opnd::UImm(Qtrue.into())); - return KeepCompiling; - } - _ if val_type.is_imm() || val_type.is_specific() => { - // guaranteed not to match T_STRING/T_ARRAY/T_HASH - let stack_ret = ctx.stack_push(Type::False); - asm.mov(stack_ret, Opnd::UImm(Qfalse.into())); - return KeepCompiling; - } + match val_type.known_value_type() { + Some(value_type) => { + if value_type == type_val { + jit_putobject(jit, ctx, asm, Qtrue); + return KeepCompiling; + } else { + jit_putobject(jit, ctx, asm, Qfalse); + return KeepCompiling; + } + }, _ => (), } @@ -2469,7 +2497,8 @@ fn gen_equality_specialized( // Otherwise guard that b is a T_STRING (from type info) or String (from runtime guard) let btype = ctx.get_opnd_type(StackOpnd(0)); - if btype != Type::TString && btype != Type::CString { + if btype.known_value_type() != Some(RUBY_T_STRING) { + mov(cb, REG0, C_ARG_REGS[1]); // Note: any T_STRING is valid here, but we check for a ::String for simplicity // To pass a mutable static variable (rb_cString) requires an unsafe block jit_guard_known_klass( @@ -3374,52 +3403,48 @@ fn jit_guard_known_klass( ) { let val_type = ctx.get_opnd_type(insn_opnd); + if val_type.known_class() == Some(known_klass) { + // We already know from type information that this is a match + return; + } + if unsafe { known_klass == rb_cNilClass } { assert!(!val_type.is_heap()); - if val_type != Type::Nil { - assert!(val_type.is_unknown()); + assert!(val_type.is_unknown()); - asm.comment("guard object is nil"); - asm.cmp(obj_opnd, Qnil.into()); - jit_chain_guard(JCC_JNE, jit, ctx, asm, ocb, max_chain_depth, side_exit); + asm.comment("guard object is nil"); + asm.cmp(obj_opnd, Qnil.into()); + jit_chain_guard(JCC_JNE, jit, ctx, asm, ocb, max_chain_depth, side_exit); - ctx.upgrade_opnd_type(insn_opnd, Type::Nil); - } + ctx.upgrade_opnd_type(insn_opnd, Type::Nil); } else if unsafe { known_klass == rb_cTrueClass } { assert!(!val_type.is_heap()); - if val_type != Type::True { - assert!(val_type.is_unknown()); + assert!(val_type.is_unknown()); - asm.comment("guard object is true"); - asm.cmp(obj_opnd, Qtrue.into()); - jit_chain_guard(JCC_JNE, jit, ctx, asm, ocb, max_chain_depth, side_exit); + asm.comment("guard object is true"); + asm.cmp(obj_opnd, Qtrue.into()); + jit_chain_guard(JCC_JNE, jit, ctx, asm, ocb, max_chain_depth, side_exit); - ctx.upgrade_opnd_type(insn_opnd, Type::True); - } + ctx.upgrade_opnd_type(insn_opnd, Type::True); } else if unsafe { known_klass == rb_cFalseClass } { assert!(!val_type.is_heap()); - if val_type != Type::False { - assert!(val_type.is_unknown()); + assert!(val_type.is_unknown()); - asm.comment("guard object is false"); - assert!(Qfalse.as_i32() == 0); - asm.test(obj_opnd, obj_opnd); - jit_chain_guard(JCC_JNZ, jit, ctx, asm, ocb, max_chain_depth, side_exit); + asm.comment("guard object is false"); + assert!(Qfalse.as_i32() == 0); + asm.test(obj_opnd, obj_opnd); + jit_chain_guard(JCC_JNZ, jit, ctx, asm, ocb, max_chain_depth, side_exit); - ctx.upgrade_opnd_type(insn_opnd, Type::False); - } + ctx.upgrade_opnd_type(insn_opnd, Type::False); } else if unsafe { known_klass == rb_cInteger } && sample_instance.fixnum_p() { - assert!(!val_type.is_heap()); // We will guard fixnum and bignum as though they were separate classes // BIGNUM can be handled by the general else case below - if val_type != Type::Fixnum || !val_type.is_imm() { - assert!(val_type.is_unknown()); + assert!(val_type.is_unknown()); - asm.comment("guard object is fixnum"); - asm.test(obj_opnd, Opnd::Imm(RUBY_FIXNUM_FLAG as i64)); - jit_chain_guard(JCC_JZ, jit, ctx, asm, ocb, max_chain_depth, side_exit); - ctx.upgrade_opnd_type(insn_opnd, Type::Fixnum); - } + asm.comment("guard object is fixnum"); + asm.test(obj_opnd, Opnd::Imm(RUBY_FIXNUM_FLAG as i64)); + jit_chain_guard(JCC_JZ, jit, ctx, asm, ocb, max_chain_depth, side_exit); + ctx.upgrade_opnd_type(insn_opnd, Type::Fixnum); } else if unsafe { known_klass == rb_cSymbol } && sample_instance.static_sym_p() { assert!(!val_type.is_heap()); // We will guard STATIC vs DYNAMIC as though they were separate classes @@ -3547,23 +3572,25 @@ fn jit_rb_obj_not( ) -> bool { let recv_opnd = ctx.get_opnd_type(StackOpnd(0)); - if recv_opnd == Type::Nil || recv_opnd == Type::False { - add_comment(cb, "rb_obj_not(nil_or_false)"); - ctx.stack_pop(1); - let out_opnd = ctx.stack_push(Type::True); - mov(cb, out_opnd, uimm_opnd(Qtrue.into())); - } else if recv_opnd.is_heap() || recv_opnd.is_specific() { - // Note: recv_opnd != Type::Nil && recv_opnd != Type::False. - add_comment(cb, "rb_obj_not(truthy)"); - ctx.stack_pop(1); - let out_opnd = ctx.stack_push(Type::False); - mov(cb, out_opnd, uimm_opnd(Qfalse.into())); - } else { - // jit_guard_known_klass() already ran on the receiver which should - // have deduced deduced the type of the receiver. This case should be - // rare if not unreachable. - return false; + match recv_opnd.known_truthy() { + Some(false) => { + add_comment(cb, "rb_obj_not(nil_or_false)"); + ctx.stack_pop(1); + let out_opnd = ctx.stack_push(Type::True); + mov(cb, out_opnd, uimm_opnd(Qtrue.into())); + }, + Some(true) => { + // Note: recv_opnd != Type::Nil && recv_opnd != Type::False. + add_comment(cb, "rb_obj_not(truthy)"); + ctx.stack_pop(1); + let out_opnd = ctx.stack_push(Type::False); + mov(cb, out_opnd, uimm_opnd(Qfalse.into())); + }, + _ => { + return false; + }, } + true } @@ -3718,7 +3745,7 @@ fn jit_rb_str_to_s( false } -// Codegen for rb_str_concat() +// Codegen for rb_str_concat() -- *not* String#concat // Frequently strings are concatenated using "out_str << next_str". // This is common in Erb and similar templating languages. fn jit_rb_str_concat( @@ -3732,14 +3759,12 @@ fn jit_rb_str_concat( _argc: i32, _known_recv_class: *const VALUE, ) -> bool { + // The << operator can accept integer codepoints for characters + // as the argument. We only specially optimise string arguments. + // If the peeked-at compile time argument is something other than + // a string, assume it won't be a string later either. let comptime_arg = jit_peek_at_stack(jit, ctx, 0); - let comptime_arg_type = ctx.get_opnd_type(StackOpnd(0)); - - // String#<< can take an integer codepoint as an argument, but we don't optimise that. - // Also, a non-string argument would have to call .to_str on itself before being treated - // as a string, and that would require saving pc/sp, which we don't do here. - // TODO: figure out how we should optimise a string-subtype argument here - if comptime_arg_type != Type::CString && comptime_arg.class_of() != unsafe { rb_cString } { + if ! unsafe { RB_TYPE_P(comptime_arg, RUBY_T_STRING) } { return false; } @@ -3747,18 +3772,25 @@ fn jit_rb_str_concat( let side_exit = get_side_exit(jit, ocb, ctx); // Guard that the argument is of class String at runtime. - jit_guard_known_klass( - jit, - ctx, - cb, - ocb, - unsafe { rb_cString }, - ctx.stack_opnd(0), - StackOpnd(0), - comptime_arg, - SEND_MAX_DEPTH, - side_exit, - ); + let insn_opnd = StackOpnd(0); + let arg_opnd = ctx.stack_opnd(0); + mov(cb, REG0, arg_opnd); + let arg_type = ctx.get_opnd_type(insn_opnd); + + if arg_type != Type::CString && arg_type != Type::TString { + if !arg_type.is_heap() { + add_comment(cb, "guard arg not immediate"); + test(cb, REG0, imm_opnd(RUBY_IMMEDIATE_MASK as i64)); + jnz_ptr(cb, side_exit); + cmp(cb, REG0, imm_opnd(Qnil.into())); + jbe_ptr(cb, side_exit); + + ctx.upgrade_opnd_type(insn_opnd, Type::UnknownHeap); + } + guard_object_is_string(cb, REG0, REG1, side_exit); + // We know this has type T_STRING, but not necessarily that it's a ::String + ctx.upgrade_opnd_type(insn_opnd, Type::TString); + } let concat_arg = ctx.stack_pop(1); let recv = ctx.stack_pop(1); @@ -3781,7 +3813,7 @@ fn jit_rb_str_concat( test(cb, REG0, uimm_opnd(RUBY_ENCODING_MASK as u64)); let enc_mismatch = cb.new_label("enc_mismatch".to_string()); - jne_label(cb, enc_mismatch); + jnz_label(cb, enc_mismatch); // If encodings match, call the simple append function and jump to return call_ptr(cb, REG0, rb_yjit_str_simple_append as *const u8); @@ -5637,6 +5669,13 @@ fn gen_getblockparamproxy( cb: &mut CodeBlock, ocb: &mut OutlinedCb, ) -> CodegenStatus { + if !jit_at_current_insn(jit) { + defer_compilation(jit, ctx, cb, ocb); + return EndBlock; + } + + let starting_context = *ctx; // make a copy for use with jit_chain_guard + // A mirror of the interpreter code. Checking for the case // where it's pushing rb_block_param_proxy. let side_exit = get_side_exit(jit, ocb, ctx); @@ -5644,6 +5683,15 @@ fn gen_getblockparamproxy( // EP level let level = jit_get_arg(jit, 1).as_u32(); + // Peek at the block handler so we can check whether it's nil + let comptime_handler = jit_peek_at_block_handler(jit, level); + + // When a block handler is present, it should always be a GC-guarded + // pointer (VM_BH_ISEQ_BLOCK_P) + if comptime_handler.as_u64() != 0 && comptime_handler.as_u64() & 0x3 != 0x1 { + return CantCompile; + } + // Load environment pointer EP from CFP gen_get_ep(cb, REG0, level); @@ -5672,27 +5720,54 @@ fn gen_getblockparamproxy( ), ); - // Block handler is a tagged pointer. Look at the tag. 0x03 is from VM_BH_ISEQ_BLOCK_P(). - and(cb, REG0_8, imm_opnd(0x3)); + // Specialize compilation for the case where no block handler is present + if comptime_handler.as_u64() == 0 { + // Bail if there is a block handler + cmp(cb, REG0, uimm_opnd(0)); - // Bail unless VM_BH_ISEQ_BLOCK_P(bh). This also checks for null. - cmp(cb, REG0_8, imm_opnd(0x1)); - jnz_ptr( - cb, - counted_exit!(ocb, side_exit, gbpp_block_handler_not_iseq), - ); + jit_chain_guard( + JCC_JNZ, + jit, + &starting_context, + cb, + ocb, + SEND_MAX_DEPTH, + side_exit, + ); - // Push rb_block_param_proxy. It's a root, so no need to use jit_mov_gc_ptr. - mov( - cb, - REG0, - const_ptr_opnd(unsafe { rb_block_param_proxy }.as_ptr()), - ); - assert!(!unsafe { rb_block_param_proxy }.special_const_p()); - let top = ctx.stack_push(Type::UnknownHeap); - mov(cb, top, REG0); + jit_putobject(jit, ctx, cb, Qnil); + } else { + // Block handler is a tagged pointer. Look at the tag. 0x03 is from VM_BH_ISEQ_BLOCK_P(). + and(cb, REG0_8, imm_opnd(0x3)); - KeepCompiling + // Bail unless VM_BH_ISEQ_BLOCK_P(bh). This also checks for null. + cmp(cb, REG0_8, imm_opnd(0x1)); + + jit_chain_guard( + JCC_JNZ, + jit, + &starting_context, + cb, + ocb, + SEND_MAX_DEPTH, + side_exit, + ); + + // Push rb_block_param_proxy. It's a root, so no need to use jit_mov_gc_ptr. + mov( + cb, + REG0, + const_ptr_opnd(unsafe { rb_block_param_proxy }.as_ptr()), + ); + assert!(!unsafe { rb_block_param_proxy }.special_const_p()); + + let top = ctx.stack_push(Type::Unknown); + mov(cb, top, REG0); + } + + jump_to_next_insn(jit, ctx, cb, ocb); + + EndBlock } fn gen_getblockparam( diff --git a/yjit/src/core.rs b/yjit/src/core.rs index ddcc22a2bf66ba..3b33360b90c6d0 100644 --- a/yjit/src/core.rs +++ b/yjit/src/core.rs @@ -129,6 +129,60 @@ impl Type { } } + /// Returns an Option with the T_ value type if it is known, otherwise None + pub fn known_value_type(&self) -> Option { + match self { + Type::Nil => Some(RUBY_T_NIL), + Type::True => Some(RUBY_T_TRUE), + Type::False => Some(RUBY_T_FALSE), + Type::Fixnum => Some(RUBY_T_FIXNUM), + Type::Flonum => Some(RUBY_T_FLOAT), + Type::Array => Some(RUBY_T_ARRAY), + Type::Hash => Some(RUBY_T_HASH), + Type::ImmSymbol | Type::HeapSymbol => Some(RUBY_T_SYMBOL), + Type::TString | Type::CString => Some(RUBY_T_STRING), + Type::Unknown | Type::UnknownImm | Type::UnknownHeap => None + } + } + + /// Returns an Option with the class if it is known, otherwise None + pub fn known_class(&self) -> Option { + unsafe { + match self { + Type::Nil => Some(rb_cNilClass), + Type::True => Some(rb_cTrueClass), + Type::False => Some(rb_cFalseClass), + Type::Fixnum => Some(rb_cInteger), + Type::Flonum => Some(rb_cFloat), + Type::ImmSymbol | Type::HeapSymbol => Some(rb_cSymbol), + Type::CString => Some(rb_cString), + _ => None, + } + } + } + + /// Returns an Option with the exact value if it is known, otherwise None + #[allow(unused)] // not yet used + pub fn known_exact_value(&self) -> Option { + match self { + Type::Nil => Some(Qnil), + Type::True => Some(Qtrue), + Type::False => Some(Qfalse), + _ => None, + } + } + + /// Returns an Option with the exact value if it is known, otherwise None + pub fn known_truthy(&self) -> Option { + match self { + Type::Nil => Some(false), + Type::False => Some(false), + Type::UnknownHeap => Some(true), + Type::Unknown | Type::UnknownImm => None, + _ => Some(true) + } + } + /// Compute a difference between two value types /// Returns 0 if the two are the same /// Returns > 0 if different but compatible diff --git a/yjit/src/cruby.rs b/yjit/src/cruby.rs index bb8dca46a7d478..1c31b8c1494c69 100644 --- a/yjit/src/cruby.rs +++ b/yjit/src/cruby.rs @@ -135,6 +135,9 @@ extern "C" { #[link_name = "rb_get_cfp_ep"] pub fn get_cfp_ep(cfp: CfpPtr) -> *mut VALUE; + #[link_name = "rb_get_cfp_ep_level"] + pub fn get_cfp_ep_level(cfp: CfpPtr, lv: u32) -> *const VALUE; + #[link_name = "rb_get_cme_def_type"] pub fn get_cme_def_type(cme: *const rb_callable_method_entry_t) -> rb_method_type_t; diff --git a/yjit/yjit.mk b/yjit/yjit.mk index eb1f5d1fe19d02..9e3155deb33195 100644 --- a/yjit/yjit.mk +++ b/yjit/yjit.mk @@ -25,13 +25,17 @@ yjit-static-lib-no: $(ECHO) 'Error: Tried to build YJIT without configuring it first. Check `make showconfig`?' @false -yjit-static-lib-dev: - $(ECHO) 'building Rust YJIT (dev mode)' +yjit-static-lib-cargo: + $(ECHO) 'building Rust YJIT ($(YJIT_SUPPORT) mode)' $(Q)$(CHDIR) $(top_srcdir)/yjit && \ CARGO_TARGET_DIR='$(CARGO_TARGET_DIR)' \ CARGO_TERM_PROGRESS_WHEN='never' \ $(CARGO) $(CARGO_VERBOSE) build $(CARGO_BUILD_ARGS) +yjit-static-lib-dev: yjit-static-lib-cargo +yjit-static-lib-dev_nodebug: yjit-static-lib-cargo +yjit-static-lib-stats: yjit-static-lib-cargo + # This PHONY prerequisite makes it so that we always run cargo. When there are # no Rust changes on rebuild, Cargo does not touch the mtime of the static # library and GNU make avoids relinking. $(empty) seems to be important to