python-utils-r1.eclass: Enable python3_9
[gentoo.git] / eclass / ruby-ng.eclass
1 # Copyright 1999-2020 Gentoo Authors
2 # Distributed under the terms of the GNU General Public License v2
3
4 # @ECLASS: ruby-ng.eclass
5 # @MAINTAINER:
6 # Ruby herd <ruby@gentoo.org>
7 # @AUTHOR:
8 # Author: Diego E. Pettenò <flameeyes@gentoo.org>
9 # Author: Alex Legler <a3li@gentoo.org>
10 # Author: Hans de Graaff <graaff@gentoo.org>
11 # @SUPPORTED_EAPIS: 4 5 6 7
12 # @BLURB: An eclass for installing Ruby packages with proper support for multiple Ruby slots.
13 # @DESCRIPTION:
14 # The Ruby eclass is designed to allow an easier installation of Ruby packages
15 # and their incorporation into the Gentoo Linux system.
16 #
17 # Currently available targets are listed in ruby-utils.eclass
18 #
19 # This eclass does not define the implementation of the configure,
20 # compile, test, or install phases. Instead, the default phases are
21 # used.  Specific implementations of these phases can be provided in
22 # the ebuild either to be run for each Ruby implementation, or for all
23 # Ruby implementations, as follows:
24 #
25 #  * each_ruby_configure
26 #  * all_ruby_configure
27
28 # @ECLASS-VARIABLE: USE_RUBY
29 # @DEFAULT_UNSET
30 # @REQUIRED
31 # @DESCRIPTION:
32 # This variable contains a space separated list of targets (see above) a package
33 # is compatible to. It must be set before the `inherit' call. There is no
34 # default. All ebuilds are expected to set this variable.
35
36 # @ECLASS-VARIABLE: RUBY_PATCHES
37 # @DEFAULT_UNSET
38 # @DESCRIPTION:
39 # A String or Array of filenames of patches to apply to all implementations.
40
41 # @ECLASS-VARIABLE: RUBY_OPTIONAL
42 # @DEFAULT_UNSET
43 # @DESCRIPTION:
44 # Set the value to "yes" to make the dependency on a Ruby interpreter
45 # optional and then ruby_implementations_depend() to help populate
46 # BDEPEND, DEPEND and RDEPEND.
47
48 # @ECLASS-VARIABLE: RUBY_S
49 # @DEFAULT_UNSET
50 # @DESCRIPTION:
51 # If defined this variable determines the source directory name after
52 # unpacking. This defaults to the name of the package. Note that this
53 # variable supports a wildcard mechanism to help with github tarballs
54 # that contain the commit hash as part of the directory name.
55
56 # @ECLASS-VARIABLE: RUBY_QA_ALLOWED_LIBS
57 # @DEFAULT_UNSET
58 # @DESCRIPTION:
59 # If defined this variable contains a whitelist of shared objects that
60 # are allowed to exist even if they don't link to libruby. This avoids
61 # the QA check that makes this mandatory. This is most likely not what
62 # you are looking for if you get the related "Missing links" QA warning,
63 # since the proper fix is almost always to make sure the shared object
64 # is linked against libruby. There are cases were this is not the case
65 # and the shared object is generic code to be used in some other way
66 # (e.g. selenium's firefox driver extension). When set this argument is
67 # passed to "grep -E" to remove reporting of these shared objects.
68
69 local inherits=""
70 case ${EAPI} in
71         4|5)
72                 inherits="eutils toolchain-funcs"
73                 ;;
74         6)
75                 inherits="estack toolchain-funcs"
76                 ;;
77         *)
78                 inherits="estack"
79                 ;;
80 esac
81
82 inherit ${inherits} multilib ruby-utils
83
84 EXPORT_FUNCTIONS src_unpack src_prepare src_configure src_compile src_test src_install pkg_setup
85
86 case ${EAPI} in
87         0|1|2|3)
88                 die "Unsupported EAPI=${EAPI} (too old) for ruby-ng.eclass" ;;
89         4|5|6|7)
90                 # S is no longer automatically assigned when it doesn't exist.
91                 S="${WORKDIR}"
92                 ;;
93         *)
94                 die "Unknown EAPI=${EAPI} for ruby-ng.eclass"
95 esac
96
97 # @FUNCTION: ruby_implementation_depend
98 # @USAGE: target [comparator [version]]
99 # @RETURN: Package atom of a Ruby implementation to be used in dependencies.
100 # @DESCRIPTION:
101 # This function returns the formal package atom for a Ruby implementation.
102 #
103 # `target' has to be one of the valid values for USE_RUBY (see above)
104 #
105 # Set `comparator' and `version' to include a comparator (=, >=, etc.) and a
106 # version string to the returned string
107 ruby_implementation_depend() {
108         _ruby_implementation_depend $1
109 }
110
111 # @FUNCTION: _ruby_get_all_impls
112 # @INTERNAL
113 # @RETURN: list of valid values in USE_RUBY
114 # Return a list of valid implementations in USE_RUBY, skipping the old
115 # implementations that are no longer supported.
116 _ruby_get_all_impls() {
117         local i
118         for i in ${USE_RUBY}; do
119                 case ${i} in
120                         # removed implementations
121                         ruby19|ruby20|ruby21|ruby22|ruby23|jruby)
122                                 ;;
123                         *)
124                                 echo ${i};;
125                 esac
126         done
127 }
128
129 # @FUNCTION: ruby_samelib
130 # @RETURN: use flag string with current ruby implementations
131 # @DESCRIPTION:
132 # Convenience function to output the use dependency part of a
133 # dependency. Used as a building block for ruby_add_rdepend() and
134 # ruby_add_bdepend(), but may also be useful in an ebuild to specify
135 # more complex dependencies.
136 ruby_samelib() {
137         local res=
138         for _ruby_implementation in $(_ruby_get_all_impls); do
139                 has -${_ruby_implementation} $@ || \
140                         res="${res}ruby_targets_${_ruby_implementation}(-)?,"
141         done
142
143         echo "[${res%,}]"
144 }
145
146 _ruby_atoms_samelib_generic() {
147         eshopts_push -o noglob
148         echo "RUBYTARGET? ("
149         for token in $*; do
150                 case "$token" in
151                         "||" | "(" | ")" | *"?")
152                                 echo "${token}" ;;
153                         *])
154                                 echo "${token%[*}[RUBYTARGET(-),${token/*[}" ;;
155                         *)
156                                 echo "${token}[RUBYTARGET(-)]" ;;
157                 esac
158         done
159         echo ")"
160         eshopts_pop
161 }
162
163 # @FUNCTION: ruby_implementation_command
164 # @RETURN: the path to the given ruby implementation
165 # @DESCRIPTION:
166 # Not all implementations have the same command basename as the
167 # target; This function translate between the two
168 ruby_implementation_command() {
169         local _ruby_name=$1
170
171         # Add all USE_RUBY values where the flag name diverts from the binary here
172
173         echo $(type -p ${_ruby_name} 2>/dev/null)
174 }
175
176 _ruby_atoms_samelib() {
177         local atoms=$(_ruby_atoms_samelib_generic "$*")
178
179         for _ruby_implementation in $(_ruby_get_all_impls); do
180                 echo "${atoms//RUBYTARGET/ruby_targets_${_ruby_implementation}}"
181         done
182 }
183
184 _ruby_wrap_conditions() {
185         local conditions="$1"
186         local atoms="$2"
187
188         for condition in $conditions; do
189                 atoms="${condition}? ( ${atoms} )"
190         done
191
192         echo "$atoms"
193 }
194
195 # @FUNCTION: ruby_add_rdepend
196 # @USAGE: dependencies
197 # @DESCRIPTION:
198 # Adds the specified dependencies, with use condition(s) to RDEPEND,
199 # taking the current set of ruby targets into account. This makes sure
200 # that all ruby dependencies of the package are installed for the same
201 # ruby targets. Use this function for all ruby dependencies instead of
202 # setting RDEPEND yourself. The list of atoms uses the same syntax as
203 # normal dependencies.
204 #
205 # Note: runtime dependencies are also added as build-time test
206 # dependencies.
207 ruby_add_rdepend() {
208         case $# in
209                 1) ;;
210                 2)
211                         case ${EAPI} in
212                                 4|5|6)
213                                         [[ "${GENTOO_DEV}" == "yes" ]] && eqawarn "You can now use the usual syntax in ruby_add_rdepend for $CATEGORY/$PF"
214                                         ruby_add_rdepend "$(_ruby_wrap_conditions "$1" "$2")"
215                                         return
216                                         ;;
217                                 *)
218                                         die "Use the usual depend syntax with a single argument in ruby_add_rdepend"
219                                         ;;
220                         esac
221                         ;;
222                 *)
223                         die "bad number of arguments to $0"
224                         ;;
225         esac
226
227         local dependency=$(_ruby_atoms_samelib "$1")
228
229         RDEPEND="${RDEPEND} $dependency"
230
231         # Add the dependency as a test-dependency since we're going to
232         # execute the code during test phase.
233         case ${EAPI} in
234                 4|5|6) DEPEND="${DEPEND} test? ( ${dependency} )" ;;
235                 *) BDEPEND="${BDEPEND} test? ( ${dependency} )" ;;
236         esac
237         if ! has test "$IUSE"; then
238                 IUSE+=" test"
239                 RESTRICT+=" !test? ( test )"
240         fi
241 }
242
243 # @FUNCTION: ruby_add_bdepend
244 # @USAGE: dependencies
245 # @DESCRIPTION:
246 # Adds the specified dependencies, with use condition(s) to DEPEND (or
247 # BDEPEND in EAPI7), taking the current set of ruby targets into
248 # account. This makes sure that all ruby dependencies of the package are
249 # installed for the same ruby targets. Use this function for all ruby
250 # dependencies instead of setting DEPEND or BDEPEND yourself. The list
251 # of atoms uses the same syntax as normal dependencies.
252 ruby_add_bdepend() {
253         case $# in
254                 1) ;;
255                 2)
256                         case ${EAPI} in
257                                 4|5|6)
258                                         [[ "${GENTOO_DEV}" == "yes" ]] && eqawarn "You can now use the usual syntax in ruby_add_bdepend for $CATEGORY/$PF"
259                                         ruby_add_bdepend "$(_ruby_wrap_conditions "$1" "$2")"
260                                         return
261                                         ;;
262                                 *)
263                                         die "Use the usual depend syntax with a single argument in ruby_add_bdepend"
264                                         ;;
265                         esac
266                         ;;
267                 *)
268                         die "bad number of arguments to $0"
269                         ;;
270         esac
271
272         local dependency=$(_ruby_atoms_samelib "$1")
273
274         case ${EAPI} in
275                 4|5|6) DEPEND="${DEPEND} $dependency" ;;
276                 *) BDEPEND="${BDEPEND} $dependency" ;;
277         esac
278         RDEPEND="${RDEPEND}"
279 }
280
281 # @FUNCTION: ruby_add_depend
282 # @USAGE: dependencies
283 # @DESCRIPTION:
284 # Adds the specified dependencies to DEPEND in EAPI7, similar to
285 # ruby_add_bdepend.
286 ruby_add_depend() {
287         case ${EAPI} in
288                 4|5|6) die "only available in EAPI 7 and newer" ;;
289                 *) ;;
290         esac
291
292         case $# in
293                 1) ;;
294                 *) die "bad number of arguments to $0" ;;
295         esac
296
297         local dependency=$(_ruby_atoms_samelib "$1")
298
299         DEPEND="${DEPEND} $dependency"
300 }
301
302 # @FUNCTION: ruby_get_use_implementations
303 # @DESCRIPTION:
304 # Gets an array of ruby use targets enabled by the user
305 ruby_get_use_implementations() {
306         local i implementation
307         for implementation in $(_ruby_get_all_impls); do
308                 use ruby_targets_${implementation} && i+=" ${implementation}"
309         done
310         echo $i
311 }
312
313 # @FUNCTION: ruby_get_use_targets
314 # @DESCRIPTION:
315 # Gets an array of ruby use targets that the ebuild sets
316 ruby_get_use_targets() {
317         local t implementation
318         for implementation in $(_ruby_get_all_impls); do
319                 t+=" ruby_targets_${implementation}"
320         done
321         echo $t
322 }
323
324 # @FUNCTION: ruby_implementations_depend
325 # @RETURN: Dependencies suitable for injection into DEPEND and RDEPEND.
326 # @DESCRIPTION:
327 # Produces the dependency string for the various implementations of ruby
328 # which the package is being built against. This should not be used when
329 # RUBY_OPTIONAL is unset but must be used if RUBY_OPTIONAL=yes. Do not
330 # confuse this function with ruby_implementation_depend().
331 #
332 # @EXAMPLE:
333 # EAPI=7
334 # RUBY_OPTIONAL=yes
335 #
336 # inherit ruby-ng
337 # ...
338 # DEPEND="ruby? ( $(ruby_implementations_depend) )"
339 # RDEPEND="${DEPEND}"
340 ruby_implementations_depend() {
341         local depend
342         for _ruby_implementation in $(_ruby_get_all_impls); do
343                 depend="${depend}${depend+ }ruby_targets_${_ruby_implementation}? ( $(ruby_implementation_depend $_ruby_implementation) )"
344         done
345         echo "${depend}"
346 }
347
348 IUSE+=" $(ruby_get_use_targets)"
349 # If you specify RUBY_OPTIONAL you also need to take care of
350 # ruby useflag and dependency.
351 if [[ ${RUBY_OPTIONAL} != yes ]]; then
352         DEPEND="${DEPEND} $(ruby_implementations_depend)"
353         RDEPEND="${RDEPEND} $(ruby_implementations_depend)"
354         REQUIRED_USE+=" || ( $(ruby_get_use_targets) )"
355         case ${EAPI} in
356                 4|5|6) ;;
357                 *) BDEPEND="${BDEPEND} $(ruby_implementations_depend)" ;;
358         esac
359 fi
360
361 _ruby_invoke_environment() {
362         old_S=${S}
363         if [ -z "${RUBY_S}" ]; then
364                 sub_S=${P}
365         else
366                 sub_S=${RUBY_S}
367         fi
368
369         # Special case, for the always-lovely GitHub fetches. With this,
370         # we allow the star glob to just expand to whatever directory it's
371         # called.
372         if [[ "${sub_S}" = *"*"* ]]; then
373                 pushd "${WORKDIR}"/all &>/dev/null || die
374                 # use an array to trigger filename expansion
375                 # fun fact: this expansion fails in src_unpack() but the original
376                 # code did not have any checks for failed expansion, so we can't
377                 # really add one now without redesigning stuff hard.
378                 sub_S=( ${sub_S} )
379                 if [[ ${#sub_S[@]} -gt 1 ]]; then
380                         die "sub_S did expand to multiple paths: ${sub_S[*]}"
381                 fi
382                 popd &>/dev/null || die
383         fi
384
385         environment=$1; shift
386
387         my_WORKDIR="${WORKDIR}"/${environment}
388         S="${my_WORKDIR}"/"${sub_S}"
389
390         if [[ -d "${S}" ]]; then
391                 pushd "$S" &>/dev/null || die
392         elif [[ -d "${my_WORKDIR}" ]]; then
393                 pushd "${my_WORKDIR}" &>/dev/null || die
394         else
395                 pushd "${WORKDIR}" &>/dev/null || die
396         fi
397
398         ebegin "Running ${_PHASE:-${EBUILD_PHASE}} phase for $environment"
399         "$@"
400         popd &>/dev/null || die
401
402         S=${old_S}
403 }
404
405 _ruby_each_implementation() {
406         local invoked=no
407         for _ruby_implementation in $(_ruby_get_all_impls); do
408                 # only proceed if it's requested
409                 use ruby_targets_${_ruby_implementation} || continue
410
411                 RUBY=$(ruby_implementation_command ${_ruby_implementation})
412                 invoked=yes
413
414                 if [[ -n "$1" ]]; then
415                         _ruby_invoke_environment ${_ruby_implementation} "$@"
416                 fi
417
418                 unset RUBY
419         done
420
421         if [[ ${invoked} == "no" ]]; then
422                 eerror "You need to select at least one compatible Ruby installation target via RUBY_TARGETS in make.conf."
423                 eerror "Compatible targets for this package are: $(_ruby_get_all_impls)"
424                 eerror
425                 eerror "See https://www.gentoo.org/proj/en/prog_lang/ruby/index.xml#doc_chap3 for more information."
426                 eerror
427                 die "No compatible Ruby target selected."
428         fi
429 }
430
431 # @FUNCTION: ruby-ng_pkg_setup
432 # @DESCRIPTION:
433 # Check whether at least one ruby target implementation is present.
434 ruby-ng_pkg_setup() {
435         # This only checks that at least one implementation is present
436         # before doing anything; by leaving the parameters empty we know
437         # it's a special case.
438         _ruby_each_implementation
439 }
440
441 # @FUNCTION: ruby-ng_src_unpack
442 # @DESCRIPTION:
443 # Unpack the source archive.
444 ruby-ng_src_unpack() {
445         mkdir "${WORKDIR}"/all
446         pushd "${WORKDIR}"/all &>/dev/null || die
447
448         # We don't support an each-unpack, it's either all or nothing!
449         if type all_ruby_unpack &>/dev/null; then
450                 _ruby_invoke_environment all all_ruby_unpack
451         else
452                 [[ -n ${A} ]] && unpack ${A}
453         fi
454
455         popd &>/dev/null || die
456 }
457
458 _ruby_apply_patches() {
459         case ${EAPI} in
460                 4|5)
461                         for patch in "${RUBY_PATCHES[@]}"; do
462                                 if [ -f "${patch}" ]; then
463                                         epatch "${patch}"
464                                 elif [ -f "${FILESDIR}/${patch}" ]; then
465                                         epatch "${FILESDIR}/${patch}"
466                                 else
467                                         die "Cannot find patch ${patch}"
468                                 fi
469                         done
470                         ;;
471                 6)
472                         if [[ -n ${RUBY_PATCHES[@]} ]]; then
473                            eqawarn "RUBY_PATCHES is no longer supported, use PATCHES instead"
474                         fi
475                         ;;
476                 *)
477                         if [[ -n ${RUBY_PATCHES[@]} ]]; then
478                                 die "RUBY_PATCHES is no longer supported, use PATCHES instead"
479                         fi
480                         ;;
481         esac
482
483         # This is a special case: instead of executing just in the special
484         # "all" environment, this will actually copy the effects on _all_
485         # the other environments, and is thus executed before the copy
486         type all_ruby_prepare &>/dev/null && all_ruby_prepare
487 }
488
489 _ruby_source_copy() {
490         # Until we actually find a reason not to, we use hardlinks, this
491         # should reduce the amount of disk space that is wasted by this.
492         cp -prlP all ${_ruby_implementation} \
493                 || die "Unable to copy ${_ruby_implementation} environment"
494 }
495
496 # @FUNCTION: ruby-ng_src_prepare
497 # @DESCRIPTION:
498 # Apply patches and prepare versions for each ruby target
499 # implementation. Also carry out common clean up tasks.
500 ruby-ng_src_prepare() {
501         # Way too many Ruby packages are prepared on OSX without removing
502         # the extra data forks, we do it here to avoid repeating it for
503         # almost every other ebuild.
504         find . -name '._*' -delete
505
506         # Handle PATCHES and user supplied patches via the default phase
507         case ${EAPI} in
508                 4|5)
509                         ;;
510                 *)
511                         _ruby_invoke_environment all default
512                         ;;
513         esac
514
515         _ruby_invoke_environment all _ruby_apply_patches
516
517         _PHASE="source copy" \
518                 _ruby_each_implementation _ruby_source_copy
519
520         if type each_ruby_prepare &>/dev/null; then
521                 _ruby_each_implementation each_ruby_prepare
522         fi
523 }
524
525 # @FUNCTION: ruby-ng_src_configure
526 # @DESCRIPTION:
527 # Configure the package.
528 ruby-ng_src_configure() {
529         if type each_ruby_configure &>/dev/null; then
530                 _ruby_each_implementation each_ruby_configure
531         fi
532
533         type all_ruby_configure &>/dev/null && \
534                 _ruby_invoke_environment all all_ruby_configure
535 }
536
537 # @FUNCTION: ruby-ng_src_compile
538 # @DESCRIPTION:
539 # Compile the package.
540 ruby-ng_src_compile() {
541         if type each_ruby_compile &>/dev/null; then
542                 _ruby_each_implementation each_ruby_compile
543         fi
544
545         type all_ruby_compile &>/dev/null && \
546                 _ruby_invoke_environment all all_ruby_compile
547 }
548
549 # @FUNCTION: ruby-ng_src_test
550 # @DESCRIPTION:
551 # Run tests for the package.
552 ruby-ng_src_test() {
553         if type each_ruby_test &>/dev/null; then
554                 _ruby_each_implementation each_ruby_test
555         fi
556
557         type all_ruby_test &>/dev/null && \
558                 _ruby_invoke_environment all all_ruby_test
559 }
560
561 _each_ruby_check_install() {
562         local scancmd=scanelf
563         # we have a Mach-O object here
564         [[ ${CHOST} == *-darwin ]] && scancmd=scanmacho
565
566         local libruby_basename=$(ruby_rbconfig_value 'LIBRUBY_SO')
567         local libruby_soname=$(basename $(${scancmd} -F "%S#F" -qS "${EPREFIX}/usr/$(get_libdir)/${libruby_basename}") 2>/dev/null)
568         local sitedir=$(ruby_rbconfig_value 'sitedir')
569         local sitelibdir=$(ruby_rbconfig_value 'sitelibdir')
570
571         # The current implementation lacks libruby (i.e.: jruby)
572         [[ -z ${libruby_soname} ]] && return 0
573
574         # Check also the gems directory, since we could be installing compiled
575         # extensions via ruby-fakegem; make sure to check only in sitelibdir, since
576         # that's what changes between two implementations (otherwise you'd get false
577         # positives now that Ruby 1.9.2 installs with the same sitedir as 1.8)
578         ${scancmd} -qnR "${D}${sitelibdir}" "${D}${sitelibdir/site_ruby/gems}" \
579                 | fgrep -v "${libruby_soname}" \
580                 | grep -E -v "${RUBY_QA_ALLOWED_LIBS}" \
581                 > "${T}"/ruby-ng-${_ruby_implementation}-mislink.log
582
583         if [[ -s "${T}"/ruby-ng-${_ruby_implementation}-mislink.log ]]; then
584                 ewarn "Extensions installed for ${_ruby_implementation} with missing links to ${libruby_soname}"
585                 ewarn $(< "${T}"/ruby-ng-${_ruby_implementation}-mislink.log )
586                 die "Missing links to ${libruby_soname}"
587         fi
588 }
589
590 # @FUNCTION: ruby-ng_src_install
591 # @DESCRIPTION:
592 # Install the package for each ruby target implementation.
593 ruby-ng_src_install() {
594         if type each_ruby_install &>/dev/null; then
595                 _ruby_each_implementation each_ruby_install
596         fi
597
598         type all_ruby_install &>/dev/null && \
599                 _ruby_invoke_environment all all_ruby_install
600
601         _PHASE="check install" \
602                 _ruby_each_implementation _each_ruby_check_install
603 }
604
605 # @FUNCTION: ruby_rbconfig_value
606 # @USAGE: rbconfig item
607 # @RETURN: Returns the value of the given rbconfig item of the Ruby interpreter in ${RUBY}.
608 ruby_rbconfig_value() {
609         echo $(${RUBY} -rrbconfig -e "puts RbConfig::CONFIG['$1']")
610 }
611
612 # @FUNCTION: doruby
613 # @USAGE: file [file...]
614 # @DESCRIPTION:
615 # Installs the specified file(s) into the sitelibdir of the Ruby interpreter in ${RUBY}.
616 doruby() {
617         [[ -z ${RUBY} ]] && die "\$RUBY is not set"
618         ( # don't want to pollute calling env
619                 sitelibdir=$(ruby_rbconfig_value 'sitelibdir')
620                 insinto ${sitelibdir#${EPREFIX}}
621                 insopts -m 0644
622                 doins "$@"
623         ) || die "failed to install $@"
624 }
625
626 # @FUNCTION: ruby_get_libruby
627 # @RETURN: The location of libruby*.so belonging to the Ruby interpreter in ${RUBY}.
628 ruby_get_libruby() {
629         ${RUBY} -rrbconfig -e 'puts File.join(RbConfig::CONFIG["libdir"], RbConfig::CONFIG["LIBRUBY"])'
630 }
631
632 # @FUNCTION: ruby_get_hdrdir
633 # @RETURN: The location of the header files belonging to the Ruby interpreter in ${RUBY}.
634 ruby_get_hdrdir() {
635         local rubyhdrdir=$(ruby_rbconfig_value 'rubyhdrdir')
636
637         if [[ "${rubyhdrdir}" = "nil" ]] ; then
638                 rubyhdrdir=$(ruby_rbconfig_value 'archdir')
639         fi
640
641         echo "${rubyhdrdir}"
642 }
643
644 # @FUNCTION: ruby_get_version
645 # @RETURN: The version of the Ruby interpreter in ${RUBY}, or what 'ruby' points to.
646 ruby_get_version() {
647         local ruby=${RUBY:-$(type -p ruby 2>/dev/null)}
648
649         echo $(${ruby} -e 'puts RUBY_VERSION')
650 }
651
652 # @FUNCTION: ruby_get_implementation
653 # @RETURN: The implementation of the Ruby interpreter in ${RUBY}, or what 'ruby' points to.
654 ruby_get_implementation() {
655         local ruby=${RUBY:-$(type -p ruby 2>/dev/null)}
656
657         case $(${ruby} --version) in
658                 *rubinius*)
659                         echo "rbx"
660                         ;;
661                 *)
662                         echo "mri"
663                         ;;
664         esac
665 }
666
667 # @FUNCTION: ruby-ng_rspec <arguments>
668 # @DESCRIPTION:
669 # This is simply a wrapper around the rspec command (executed by $RUBY})
670 # which also respects TEST_VERBOSE and NOCOLOR environment variables.
671 # Optionally takes arguments to pass on to the rspec invocation.  The
672 # environment variable RSPEC_VERSION can be used to control the specific
673 # rspec version that must be executed. It defaults to 2 for historical
674 # compatibility.
675 ruby-ng_rspec() {
676         local version=${RSPEC_VERSION-2}
677         local files="$@"
678
679         # Explicitly pass the expected spec directory since the versioned
680         # rspec wrappers don't handle this automatically.
681         if [ ${#@} -eq 0 ]; then
682                 files="spec"
683         fi
684
685         if [[ "${DEPEND}${BDEPEND}" != *"dev-ruby/rspec"* ]]; then
686                 ewarn "Missing test dependency dev-ruby/rspec"
687         fi
688
689         local rspec_params=
690         case ${NOCOLOR} in
691                 1|yes|true)
692                         rspec_params+=" --no-color"
693                         ;;
694                 *)
695                         rspec_params+=" --color"
696                         ;;
697         esac
698
699         case ${TEST_VERBOSE} in
700                 1|yes|true)
701                         rspec_params+=" --format documentation"
702                         ;;
703                 *)
704                         rspec_params+=" --format progress"
705                         ;;
706         esac
707
708         ${RUBY} -S rspec-${version} ${rspec_params} ${files} || die "rspec failed"
709 }
710
711 # @FUNCTION: ruby-ng_cucumber
712 # @DESCRIPTION:
713 # This is simply a wrapper around the cucumber command (executed by $RUBY})
714 # which also respects TEST_VERBOSE and NOCOLOR environment variables.
715 ruby-ng_cucumber() {
716         if [[ "${DEPEND}${BDEPEND}" != *"dev-util/cucumber"* ]]; then
717                 ewarn "Missing test dependency dev-util/cucumber"
718         fi
719
720         local cucumber_params=
721         case ${NOCOLOR} in
722                 1|yes|true)
723                         cucumber_params+=" --no-color"
724                         ;;
725                 *)
726                         cucumber_params+=" --color"
727                         ;;
728         esac
729
730         case ${TEST_VERBOSE} in
731                 1|yes|true)
732                         cucumber_params+=" --format pretty"
733                         ;;
734                 *)
735                         cucumber_params+=" --format progress"
736                         ;;
737         esac
738
739         ${RUBY} -S cucumber ${cucumber_params} "$@" || die "cucumber failed"
740 }
741
742 # @FUNCTION: ruby-ng_testrb-2
743 # @DESCRIPTION:
744 # This is simply a replacement for the testrb command that load the test
745 # files and execute them, with test-unit 2.x. This actually requires
746 # either an old test-unit-2 version or 2.5.1-r1 or later, as they remove
747 # their script and we installed a broken wrapper for a while.
748 # This also respects TEST_VERBOSE and NOCOLOR environment variables.
749 ruby-ng_testrb-2() {
750         if [[ "${DEPEND}${BDEPEND}" != *"dev-ruby/test-unit"* ]]; then
751                 ewarn "Missing test dependency dev-ruby/test-unit"
752         fi
753
754         local testrb_params=
755         case ${NOCOLOR} in
756                 1|yes|true)
757                         testrb_params+=" --no-use-color"
758                         ;;
759                 *)
760                         testrb_params+=" --use-color=auto"
761                         ;;
762         esac
763
764         case ${TEST_VERBOSE} in
765                 1|yes|true)
766                         testrb_params+=" --verbose=verbose"
767                         ;;
768                 *)
769                         testrb_params+=" --verbose=normal"
770                         ;;
771         esac
772
773         ${RUBY} -S testrb-2 ${testrb_params} "$@" || die "testrb-2 failed"
774 }