Ejemplo n.º 1
0
  @Test
  public void pushResolver() throws IOException {
    ValueResolver resolver =
        new ValueResolver() {

          @Override
          public Object resolve(final Object context) {
            return 1;
          }

          @Override
          public Object resolve(final Object context, final String name) {
            return 1;
          }

          @Override
          public Set<Entry<String, Object>> propertySet(final Object context) {
            return null;
          }
        };

    Map<String, Object> hash = new HashMap<>();
    hash.put("foo", "bar");
    Context ctx = Context.newBuilder(hash).push(resolver).build();
    assertEquals("bar", ctx.get("foo"));
    assertEquals(1, ctx.get("bar"));
  }
Ejemplo n.º 2
0
 /**
  * Lookup the given key inside the context stack.
  *
  * <ul>
  *   <li>Objects and hashes should be pushed onto the context stack.
  *   <li>All elements on the context stack should be accessible.
  *   <li>Multiple sections per template should be permitted.
  *   <li>Failed context lookups should be considered falsey.
  *   <li>Dotted names should be valid for Section tags.
  *   <li>Dotted names that cannot be resolved should be considered falsey.
  *   <li>Dotted Names - Context Precedence: Dotted names should be resolved against former
  *       resolutions.
  * </ul>
  *
  * @param key The object key.
  * @return The value associated to the given key or <code>null</code> if no value is found.
  */
 public Object get(final String key) {
   // '.' or 'this'
   if (MUSTACHE_THIS.equals(key) || THIS.equals(key)) {
     return model;
   }
   // '..'
   if (key.equals(PARENT)) {
     return parent == null ? null : parent.model;
   }
   // '../'
   if (key.startsWith(PARENT_ATTR)) {
     return parent == null ? null : parent.get(key.substring(PARENT_ATTR.length()));
   }
   String[] path = toPath(key);
   Object value = get(path);
   if (value == null) {
     // No luck, check the extended context.
     value = get(extendedContext, key);
     // No luck, check the data context.
     if (value == null && data != null) {
       String dataKey = key.charAt(0) == '@' ? key.substring(1) : key;
       // simple data keys will be resolved immediately, complex keys need to go down and using a
       // new context.
       value = data.get(dataKey);
       if (value == null && path.length > 1) {
         // for complex keys, a new data context need to be created per invocation,
         // bc data might changes per execution.
         Context dataContext =
             Context.newBuilder(data).resolver(MapValueResolver.INSTANCE).build();
         // don't extend the lookup further.
         dataContext.data = null;
         value = dataContext.get(dataKey);
         // destroy it!
         dataContext.destroy();
       }
     }
     // No luck, but before checking at the parent scope we need to check for
     // the 'this' qualifier. If present, no look up will be done.
     if (value == null && !path[0].equals(THIS)) {
       value = get(parent, key);
     }
   }
   return value == NULL ? null : value;
 }
Ejemplo n.º 3
0
  @SuppressWarnings("unchecked")
  @Override
  protected void merge(final Context context, final Writer writer) throws IOException {
    if (body == null) {
      return;
    }
    final String helperName;
    Helper<Object> helper = helper(name);
    Template template = body;
    final Object childContext;
    Context currentScope = context;
    if (helper == null) {
      childContext = transform(context.get(name));
      if (inverted) {
        helperName = UnlessHelper.NAME;
      } else if (childContext instanceof Iterable) {
        helperName = EachHelper.NAME;
      } else if (childContext instanceof Boolean) {
        helperName = IfHelper.NAME;
      } else if (childContext instanceof Lambda) {
        helperName = WithHelper.NAME;
        template =
            Lambdas.compile(
                handlebars,
                (Lambda<Object, Object>) childContext,
                context,
                template,
                startDelimiter,
                endDelimiter);
      } else {
        helperName = WithHelper.NAME;
        currentScope = Context.newContext(context, childContext);
      }
      // A built-in helper might be override it.
      helper = handlebars.helper(helperName);
    } else {
      helperName = name;
      childContext = transform(determineContext(context));
    }
    Options options =
        new Options.Builder(handlebars, helperName, TagType.SECTION, currentScope, template)
            .setInverse(inverse == null ? Template.EMPTY : inverse)
            .setParams(params(currentScope))
            .setHash(hash(context))
            .build();
    options.data(Context.PARAM_SIZE, this.params.size());

    CharSequence result = helper.apply(childContext, options);
    if (!isEmpty(result)) {
      writer.append(result);
    }
  }
Ejemplo n.º 4
0
 @Override
 public CharSequence apply(final Object context, final Options options) throws IOException {
   if (context == null) {
     return null;
   }
   if (options.params.length <= 0) {
     return context.toString();
   }
   Context ctx = Context.newBuilder(options.context, context).build();
   Object lookup = ctx.get(options.param(0).toString());
   if (lookup == null) {
     return null;
   }
   return lookup.toString();
 }
Ejemplo n.º 5
0
 /**
  * Lookup the given key inside the context stack.
  *
  * <ul>
  *   <li>Objects and hashes should be pushed onto the context stack.
  *   <li>All elements on the context stack should be accessible.
  *   <li>Multiple sections per template should be permitted.
  *   <li>Failed context lookups should be considered falsey.
  *   <li>Dotted names should be valid for Section tags.
  *   <li>Dotted names that cannot be resolved should be considered falsey.
  *   <li>Dotted Names - Context Precedence: Dotted names should be resolved against former
  *       resolutions.
  * </ul>
  *
  * @param key The object key.
  * @return The value associated to the given key or <code>null</code> if no value is found.
  */
 public Object get(final String key) {
   if (".".equals(key) || "this".equals(key)) {
     return model;
   }
   if (key.startsWith("../")) {
     return parent == null ? null : parent.get(key.substring("../".length()));
   }
   String[] path = toPath(key);
   Object value = get(path);
   if (value == null) {
     // No luck, check the extended context.
     value = get(extendedContext, key);
     // No luck, but before checking at the parent scope we need to check for
     // the 'this' qualifier. If present, no look up will be done.
     if (value == null && !path[0].equals("this")) {
       value = get(parent, key);
     }
   }
   return value == NULL ? null : value;
 }
Ejemplo n.º 6
0
 /**
  * Look for the specified key in an external context.
  *
  * @param external The external context.
  * @param key The associated key.
  * @return The associated value or null if not found.
  */
 private Object get(final Context external, final String key) {
   return external == null ? null : external.get(key);
 }
Ejemplo n.º 7
0
 @Override
 Object doParse(final Context scope, final Object param) {
   return scope.get((String) param);
 }