All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jruby.RubyChain Maven / Gradle / Ivy

/***** BEGIN LICENSE BLOCK *****
 * Version: EPL 2.0/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Eclipse Public
 * License Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.eclipse.org/legal/epl-v20.html
 *
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either of the GNU General Public License Version 2 or later (the "GPL"),
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the EPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the EPL, the GPL or the LGPL.
 ***** END LICENSE BLOCK *****/

package org.jruby;

import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;

import org.jruby.runtime.Block;

import org.jruby.runtime.Helpers;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.Visibility;
import org.jruby.runtime.builtin.IRubyObject;

import org.jruby.util.ByteList;

import static org.jruby.RubyEnumerator.enumeratorizeWithSize;
import static org.jruby.RubyEnumerator.SizeFn;

/**
 * Implements Enumerator::Chain
 */
@JRubyClass(name = "Enumerator::Chain")
public class RubyChain extends RubyObject {

    private IRubyObject[] enums;
    private int pos = -1;

    public static RubyClass createChainClass(Ruby runtime, RubyClass enumeratorModule) {
        RubyClass chainc = runtime.defineClassUnder("Chain", runtime.getObject(), RubyChain::new, enumeratorModule);

        chainc.includeModule(runtime.getEnumerable());
        chainc.defineAnnotatedMethods(RubyChain.class);

        return chainc;
    }

    public RubyChain(Ruby runtime, RubyClass klass) {
        super(runtime, klass);
    }

    public RubyChain(Ruby runtime, RubyClass klass, IRubyObject[] enums) {
        super(runtime, klass);
        this.enums = enums;
    }

    //
    @JRubyMethod(name = "initialize", rest = true, visibility = Visibility.PRIVATE)
    public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
        checkFrozen();

        enums = new IRubyObject[args.length];
        System.arraycopy(args, 0, enums, 0, args.length);

        return this;
    }

    public static RubyChain newChain(ThreadContext context, IRubyObject[] enums) {
        return new RubyChain(context.runtime, context.runtime.getChain(), enums);
    }

    // enum_chain_each
    @JRubyMethod(rest = true)
    public IRubyObject each(ThreadContext context, IRubyObject[] args, Block block) {
        if (!block.isGiven()) {
            return RubyEnumerator.enumeratorizeWithSize(context, this, "each", args, RubyChain::size);
        }

        for (int i = 0; i < enums.length; i++) {
            pos = i;
            Helpers.invoke(context, enums[i], "each", args, block);
        }

        return this;
    }

    /**
     * A size method suitable for lambda method reference implementation of {@link SizeFn#size(ThreadContext, IRubyObject, IRubyObject[])}
     *
     * @see SizeFn#size(ThreadContext, IRubyObject, IRubyObject[])
     */
    private static IRubyObject size(ThreadContext context, RubyChain self, IRubyObject[] args) {
        return self.size(context);
    }

    // enum_chain_rewind
    @JRubyMethod
    public IRubyObject rewind(ThreadContext context) {
        for (int i = pos; 0 <= i && pos < enums.length; i--) {
            Helpers.invokeChecked(context, enums[i], "rewind");
            pos -= 1;
        }

        return this;
    }

    @Override
    public final IRubyObject inspect() {
        return inspect(getRuntime().getCurrentContext());
    }

    @JRubyMethod
    public RubyString inspect(ThreadContext context) {

        ByteList str = new ByteList();
        str.append('#').append('<');
        str.append(getMetaClass().getRealClass().getName().getBytes());
        str.append(':').append(' ').append('[');
        for (int i = 0; i < enums.length - 1; i++) {
            str.append(RubyObject.inspect(context, enums[i]).getByteList());
            str.append(',').append(' ');
        }
        if (enums.length > 0) {
            str.append(RubyObject.inspect(context, enums[enums.length - 1]).getByteList());
        }
        str.append(']').append('>');

        return RubyString.newStringLight(context.runtime, str);
    }

    // enum_chain_size
    @JRubyMethod
    public IRubyObject size(ThreadContext context) {
        return enumChainTotalSize(context, enums);
    }

    // enum_chain_total_size
    private static IRubyObject enumChainTotalSize(ThreadContext context, IRubyObject[] args) {

        RubyFixnum total = RubyFixnum.zero(context.runtime);
        for (int i = 0; i < args.length; i++) {
            IRubyObject size = args[i].respondsTo("size") ? args[i].callMethod(context, "size") : context.nil;

            if (size.isNil() || (size instanceof RubyFloat) && size.equals(context.runtime.getFloat().getConstant("INFINITY"))) {
                return size;
            }

            if (!(size instanceof RubyInteger)) {
                return context.nil;
            }

            total = (RubyFixnum)total.callMethod("+", size);
        }

        return total;
    }

    @JRubyMethod(name = "+", required = 1)
    public IRubyObject op_plus(ThreadContext context, IRubyObject obj) {
        return RubyChain.newChain(context, new IRubyObject[] {this, obj});
    }
    
    @JRubyMethod(name = "dup")
    @Override
    public IRubyObject dup() {
        RubyChain copy = (RubyChain) super.dup();
        copy.enums = this.enums;
        copy.pos = this.pos;

        return copy;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy