summaryrefslogtreecommitdiff
path: root/java/src/json/ext/OptionsReader.java
blob: 70426d427b5d8b5722ab1e1eb1877fccd42275cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/*
 * This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
 *
 * Distributed under the Ruby license: https://www.ruby-lang.org/en/about/license.txt
 */
package json.ext;

import org.jruby.Ruby;
import org.jruby.RubyClass;
import org.jruby.RubyHash;
import org.jruby.RubyNumeric;
import org.jruby.RubyString;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ByteList;

final class OptionsReader {
    private final ThreadContext context;
    private final Ruby runtime;
    private final RubyHash opts;
    private RuntimeInfo info;

    OptionsReader(ThreadContext context, IRubyObject vOpts) {
        this.context = context;
        this.runtime = context.getRuntime();
        if (vOpts == null || vOpts.isNil()) {
            opts = null;
        } else if (vOpts.respondsTo("to_hash")) {
            opts = vOpts.convertToHash();
        } else if (vOpts.respondsTo("to_h")) {
            opts = vOpts.callMethod(context, "to_h").convertToHash();
        } else {
            opts = vOpts.convertToHash(); /* Should just raise the correct TypeError */
        }
    }

    private RuntimeInfo getRuntimeInfo() {
        if (info != null) return info;
        info = RuntimeInfo.forRuntime(runtime);
        return info;
    }

    /**
     * Efficiently looks up items with a {@link RubySymbol Symbol} key
     * @param key The Symbol name to look up for
     * @return The item in the {@link RubyHash Hash}, or <code>null</code>
     *         if not found
     */
    IRubyObject get(String key) {
        return opts == null ? null : opts.fastARef(runtime.newSymbol(key));
    }

    boolean getBool(String key, boolean defaultValue) {
        IRubyObject value = get(key);
        return value == null ? defaultValue : value.isTrue();
    }

    int getInt(String key, int defaultValue) {
        IRubyObject value = get(key);
        if (value == null) return defaultValue;
        if (!value.isTrue()) return 0;
        return RubyNumeric.fix2int(value);
    }

    /**
     * Reads the setting from the options hash. If no entry is set for this
     * key or if it evaluates to <code>false</code>, returns null; attempts to
     * coerce the value to {@link RubyString String} otherwise.
     * @param key The Symbol name to look up for
     * @return <code>null</code> if the key is not in the Hash or if
     *         its value evaluates to <code>false</code>
     * @throws RaiseException <code>TypeError</code> if the value does not
     *                        evaluate to <code>false</code> and can't be
     *                        converted to string
     */
    ByteList getString(String key) {
        RubyString str = getString(key, null);
        return str == null ? null : str.getByteList().dup();
    }

    RubyString getString(String key, RubyString defaultValue) {
        IRubyObject value = get(key);
        if (value == null || !value.isTrue()) return defaultValue;

        RubyString str = value.convertToString();
        RuntimeInfo info = getRuntimeInfo();
        if (str.encoding(context) != info.utf8.get()) {
            str = (RubyString)str.encode(context, info.utf8.get());
        }
        return str;
    }

    /**
     * Reads the setting from the options hash. If it is <code>nil</code> or
     * undefined, returns the default value given.
     * If not, ensures it is a RubyClass instance and shares the same
     * allocator as the default value (i.e. for the basic types which have
     * their specific allocators, this ensures the passed value is
     * a subclass of them).
     */
    RubyClass getClass(String key, RubyClass defaultValue) {
        IRubyObject value = get(key);

        if (value == null || value.isNil()) return defaultValue;
        return (RubyClass)value;
    }

    public RubyHash getHash(String key) {
        IRubyObject value = get(key);
        if (value == null || value.isNil()) return new RubyHash(runtime);
        return (RubyHash) value;
    }
}