LocalGlobalVariable.java

  1. /**
  2.  * **** BEGIN LICENSE BLOCK *****
  3.  * Version: EPL 1.0/GPL 2.0/LGPL 2.1
  4.  *
  5.  * The contents of this file are subject to the Eclipse Public
  6.  * License Version 1.0 (the "License"); you may not use this file
  7.  * except in compliance with the License. You may obtain a copy of
  8.  * the License at http://www.eclipse.org/legal/epl-v10.html
  9.  *
  10.  * Software distributed under the License is distributed on an "AS
  11.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  12.  * implied. See the License for the specific language governing
  13.  * rights and limitations under the License.
  14.  *
  15.  * Copyright (C) 2009-2012 Yoko Harada <yokolet@gmail.com>
  16.  *
  17.  * Alternatively, the contents of this file may be used under the terms of
  18.  * either of the GNU General Public License Version 2 or later (the "GPL"),
  19.  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  20.  * in which case the provisions of the GPL or the LGPL are applicable instead
  21.  * of those above. If you wish to allow use of your version of this file only
  22.  * under the terms of either the GPL or the LGPL, and not to allow others to
  23.  * use your version of this file under the terms of the EPL, indicate your
  24.  * decision by deleting the provisions above and replace them with the notice
  25.  * and other provisions required by the GPL or the LGPL. If you do not delete
  26.  * the provisions above, a recipient may use your version of this file under
  27.  * the terms of any one of the EPL, the GPL or the LGPL.
  28.  * **** END LICENSE BLOCK *****
  29.  */
  30. package org.jruby.embed.variable;

  31. import java.util.Set;
  32. import org.jruby.Ruby;
  33. import org.jruby.RubyObject;
  34. import org.jruby.embed.internal.BiVariableMap;
  35. import org.jruby.internal.runtime.GlobalVariables;
  36. import org.jruby.runtime.builtin.IRubyObject;

  37. /**
  38.  * An implementation of BiVariable for JSR223 style global variable. The assigned
  39.  * name is like a local variables in Java, but a global in Ruby.
  40.  *
  41.  * @author Yoko Harada <yokolet@gmail.com>
  42.  */
  43. public class LocalGlobalVariable extends GlobalVariable {
  44.     private static String pattern = "([a-zA-Z]|(_([a-zA-Z]|_|\\d)))([a-zA-Z]|_|\\d)*";

  45.     /**
  46.      * Returns an instance of this class. This factory method is used when a local
  47.      * global type variable is put into {@link BiVariableMap}.
  48.      *
  49.      * @param runtime Ruby runtime
  50.      * @param name a variable name
  51.      * @param javaObject Java object that should be assigned to.
  52.      * @return the instance of LocalGlobalVariable
  53.      */
  54.     public static BiVariable getInstance(RubyObject receiver, String name, Object... javaObject) {
  55.         if (name.matches(pattern)) {
  56.             return new LocalGlobalVariable(receiver, name, javaObject);
  57.         }
  58.         return null;
  59.     }

  60.     private LocalGlobalVariable(RubyObject receiver, String name, Object... javaObject) {
  61.         super(receiver, name, javaObject);
  62.     }

  63.     /**
  64.      * A constructor used when local global type variables are retrieved from Ruby.
  65.      *
  66.      * @param name the local global type variable name
  67.      * @param irubyObject Ruby global object
  68.      */
  69.     LocalGlobalVariable(IRubyObject receiver, String name, IRubyObject irubyObject) {
  70.         super(receiver, name, irubyObject);
  71.     }

  72.     /**
  73.      * Retrieves global variables eagerly from Ruby right after the evaluation. The
  74.      * variable names to be retrieved must be in a variable map.
  75.      *
  76.      * @param receiver receiver object returned when a script is evaluated.
  77.      * @param vars map to save retrieved global variables.
  78.      */
  79.     public static void retrieve(RubyObject receiver, BiVariableMap vars) {
  80.         if (vars.isLazy()) return;
  81.        
  82.         GlobalVariables gvars = receiver.getRuntime().getGlobalVariables();
  83.         Set<String> names = gvars.getNames();
  84.         for (String name : names) {
  85.             if (isPredefined(name)) {
  86.                 continue;
  87.             }
  88.             IRubyObject value = gvars.get(name);
  89.             String javaName = name.substring(1); // eliminates a preceding character, "$"
  90.             updateLocalGlobal((RubyObject)receiver.getRuntime().getTopSelf(), vars, javaName, value);
  91.         }
  92.     }

  93.     private static void updateLocalGlobal(RubyObject receiver, BiVariableMap vars, String name, IRubyObject value) {
  94.         BiVariable var;
  95.         if (vars.containsKey((Object) name)) {
  96.             var = vars.getVariable(receiver, name);
  97.             var.setRubyObject(value);
  98.         } else {
  99.             var = new LocalGlobalVariable(receiver, name, value);
  100.             vars.update(name, var);
  101.         }
  102.     }

  103.     /**
  104.      * Retrieves a global variable by key from Ruby runtime after the evaluation.
  105.      * This method is used when eager retrieval is off.
  106.      *
  107.      * @param runtime Ruby runtime
  108.      * @param vars map to save a retrieved global variable.
  109.      * @param key name of the global variable
  110.      */
  111.     public static void retrieveByKey(Ruby runtime, BiVariableMap vars, String key) {
  112.         GlobalVariables gvars = runtime.getGlobalVariables();
  113.         // if the specified key doesn't exist, this method is called before the
  114.         // evaluation. Don't update value in this case.
  115.         String rubyKey = ("$" + key).intern();
  116.         if (!gvars.getNames().contains(rubyKey)) return;

  117.         // the specified key is found, so let's update
  118.         IRubyObject value = gvars.get(rubyKey);
  119.         updateLocalGlobal((RubyObject)runtime.getTopSelf(), vars, key, value);
  120.     }

  121.     /**
  122.      * Returns enum type of this variable defined in {@link BiVariable}.
  123.      *
  124.      * @return this enum type, BiVariable.Type.GlobalVariable.
  125.      */
  126.     @Override
  127.     public Type getType() {
  128.         return Type.LocalGlobalVariable;
  129.     }

  130.     /**
  131.      * Returns true if the given name is a local global type variable. Unless
  132.      * returns false.
  133.      *
  134.      * @param name is a name to be checked.
  135.      * @return true if the given name is of a local global type variable.
  136.      */
  137.     public static boolean isValidName(Object name) {
  138.         return isValidName(pattern, name);
  139.     }

  140.     /**
  141.      * Injects a global value to a parsed Ruby script. This method is
  142.      * invoked during EvalUnit#run() is executed.
  143.      */
  144.     @Override
  145.     public void inject() {
  146.         synchronized (receiver.getRuntime()) {
  147.             String varname = (name.startsWith("$") ? name : "$" + name);
  148.             receiver.getRuntime().getGlobalVariables().set(varname.intern(), irubyObject);
  149.         }
  150.     }

  151.     /**
  152.      * Removes this object from {@link BiVariableMap}.
  153.      *
  154.      * @param runtime environment where a variable is removed.
  155.      */
  156.     @Override
  157.     public void remove() {
  158.         synchronized (receiver.getRuntime()) {
  159.             String varname = (name.startsWith("$") ? name : "$" + name);
  160.             receiver.getRuntime().getGlobalVariables().clear(varname.intern());
  161.         }
  162.     }
  163. }