/**
* Copyright (c) 2012-2015 Edgar Espina
*
* This file is part of Handlebars.java.
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.jknack.handlebars;
import static org.apache.commons.lang3.Validate.isTrue;
import static org.apache.commons.lang3.Validate.notNull;
import humanize.Humanize;
import java.io.IOException;
import java.util.Date;
import java.util.Locale;
import com.github.jknack.handlebars.internal.Locales;
/**
* Handlebars helper for the Humanize library.
*
* @author edgar.espina
* @since 0.5.0
*/
public enum HumanizeHelper implements Helper<Object> {
/**
* <p>
* Converts a given number to a string preceded by the corresponding binary
* International System of Units (SI) prefix.
* </p>
*
* <pre>
* {{binaryPrefix number [locale="default"]}}
* </pre>
*
* @see Humanize#binaryPrefix(Number, Locale)
*/
binaryPrefix {
@Override
public Object apply(final Object value, final Options options)
throws IOException {
isTrue(value instanceof Number, "found '%s', expected: 'number'", value);
return Humanize.binaryPrefix((Number) value, resolveLocale(options));
}
},
/**
* <p>
* Makes a phrase camel case. Spaces and underscores will be removed.
* </p>
*
* <pre>
* {{camelize stringValue [capFirst=false]}}
* </pre>
*
* @see Humanize#camelize(String, boolean)
*/
camelize {
@Override
public Object apply(final Object value, final Options options)
throws IOException {
isTrue(value instanceof String, "found '%s', expected: 'string'", value);
Boolean capFirst = options.hash("capFirst", true);
return Humanize.camelize((String) value, capFirst);
}
},
/**
* <p>
* Makes the first letter uppercase and the rest lowercase.
* </p>
*
* <pre>
* {{capitalize word}}
* </pre>
*
* @see Humanize#capitalize(String)
*/
capitalize {
@Override
public Object apply(final Object value, final Options options)
throws IOException {
isTrue(value instanceof String, "found '%s', expected: 'string'", value);
return Humanize.capitalize((String) value);
}
},
/**
* <p>
* Converts a camel case string into a human-readable name.
* </p>
*
* <pre>
* {{decamelize string [replacement=" "]}}
* </pre>
*
* @see Humanize#decamelize(String, String)
*/
decamelize {
@Override
public Object apply(final Object value, final Options options)
throws IOException {
isTrue(value instanceof String, "found '%s', expected: 'string'", value);
String replacement = options.hash("replacement", " ");
return Humanize.decamelize((String) value, replacement);
}
},
/**
* <p>
* Smartly formats the given number as a monetary amount.
* </p>
*
* <pre>
* {{formatCurrency string [locale="default"]}}
* </pre>
*
* @see Humanize#formatCurrency(Number, java.util.Locale)
*/
formatCurrency {
@Override
public Object apply(final Object value, final Options options)
throws IOException {
isTrue(value instanceof Number, "found '%s', expected: 'number'", value);
return Humanize.formatCurrency((Number) value, resolveLocale(options));
}
},
/**
* <p>
* Formats the given ratio as a percentage.
* </p>
*
* <pre>
* {{formatPercent string [locale="default"]}}
* </pre>
*
* @see Humanize#formatPercent(Number)
*/
formatPercent {
@Override
public Object apply(final Object value, final Options options)
throws IOException {
isTrue(value instanceof Number, "found '%s', expected: 'number'", value);
return Humanize.formatPercent((Number) value, resolveLocale(options));
}
},
/**
* <p>
* Converts a given number to a string preceded by the corresponding decimal
* multiplicative prefix.
* </p>
*
* <pre>
* {{metricPrefix string [locale="default"]}}
* </pre>
*
* @see Humanize#metricPrefix(Number, Locale)
*/
metricPrefix {
@Override
public Object apply(final Object value, final Options options)
throws IOException {
isTrue(value instanceof Number, "found '%s', expected: 'number'", value);
return Humanize.metricPrefix((Number) value, resolveLocale(options));
}
},
/**
* For dates that are the current day or within one day, return 'today',
* 'tomorrow' or 'yesterday', as appropriate. Otherwise, returns a string
* formatted according to a locale sensitive DateFormat.
*
* <pre>
* {{naturalDay date}}
* </pre>
*
* @see Humanize#naturalDay(Date)
*/
naturalDay {
@Override
public Object apply(final Object value, final Options options)
throws IOException {
isTrue(value instanceof Date, "found '%s', expected: 'date'", value);
return Humanize.naturalDay((Date) value);
}
},
/**
* Computes both past and future relative dates.
* <p>
* E.g. 'one day ago', 'one day from now', '10 years ago', '3 minutes from
* now', 'right now' and so on.
* </p>
*
* <pre>
* {{naturalTime date [locale="default"]}}
* </pre>
*
* @see Humanize#naturalTime(Date, Locale)
*/
naturalTime {
@Override
public Object apply(final Object value, final Options options)
throws IOException {
isTrue(value instanceof Date, "found '%s', expected: 'date'", value);
return Humanize.naturalTime((Date) value, resolveLocale(options));
}
},
/**
* Converts a number to its ordinal as a string.
* <p>
* E.g. 1 becomes '1st', 2 becomes '2nd', 3 becomes '3rd', etc.
* </p>
*
* <pre>
* {{ordinal number [locale="default"]}}
* </pre>
*
* @see Humanize#ordinal(Number, Locale)
*/
ordinal {
@Override
public Object apply(final Object value, final Options options)
throws IOException {
isTrue(value instanceof Number, "found '%s', expected: 'number'", value);
return Humanize.ordinal((Number) value, resolveLocale(options));
}
},
/**
* <p>
* Constructs a message with pluralization logic from the given template.
* </p>
* <h5>Examples:</h5>
*
* <pre>
* MessageFormat msg =
* pluralize("There {0} on {1}.::are no files::is one file::are {0}
* files");
*
* // == "There are no files on disk."
* msg.render(0, "disk");
*
* // == "There is one file on disk."
* msg.render(1, "disk");
*
* // == "There is one file on disk."
* msg.render(1000, "disk");
* </pre>
*
* <pre>
* MessageFormat msg = pluralize("nothing::one thing::{0} things");
*
* msg.render(-1); // == "nothing"
* msg.render(0); // == "nothing"
* msg.render(1); // == "one thing"
* msg.render(2); // == "2 things"
* </pre>
*
* <pre>
* MessageFormat msg = pluralize("one thing::{0} things");
*
* msg.render(-1); // == "-1 things"
* msg.render(0); // == "0 things"
* msg.render(1); // == "one thing"
* msg.render(2); // == "2 things"
* </pre>
*
* <pre>
* {{pluralize "pattern" arg0, arg1, ..., argn [locale="default"]}}
* </pre>
*
* @see Humanize#pluralize(String, Locale)
*/
pluralize {
@Override
public Object apply(final Object value, final Options options)
throws IOException {
isTrue(value instanceof String, "found '%s', expected: 'string'", value);
return Humanize.pluralizeFormat((String) value, resolveLocale(options))
.render(options.params);
}
},
/**
* <p>
* Transforms a text into a representation suitable to be used in an URL.
* </p>
* <table border="0" cellspacing="0" cellpadding="3" width="100%">
* <tr>
* <th class="colFirst">Input</th>
* <th class="colLast">Output</th>
* </tr>
* <tr>
* <td>"J'étudie le français"</td>
* <td>"jetudie-le-francais"</td>
* </tr>
* <tr>
* <td>"Lo siento, no hablo español."</td>
* <td>"lo-siento-no-hablo-espanol"</td>
* </tr>
* </table>
*
* <pre>
* {{slugify string}}
* </pre>
*
* @see Humanize#slugify(String)
*/
slugify {
@Override
public Object apply(final Object value, final Options options)
throws IOException {
isTrue(value instanceof String, "found '%s', expected: 'string'", value);
return Humanize.slugify((String) value);
}
},
/**
* <p>
* Converts a big number to a friendly text representation. Accepts values
* ranging from thousands to googols. Uses BigDecimal.
* </p>
*
* <pre>
* {{spellNumber number [locale="default"]}}
* </pre>
*
* @see Humanize#spellBigNumber(Number, Locale)
*/
spellNumber {
@Override
public Object apply(final Object value, final Options options)
throws IOException {
isTrue(value instanceof Number, "found '%s', expected: 'number'", value);
return Humanize.spellBigNumber((Number) value, resolveLocale(options));
}
},
/**
* <p>
* For decimal digits [0-9], returns the number spelled out. Otherwise,
* returns the number as string.
* </p>
*
* <pre>
* {{spellDigit digit [locale="default"]}}
* </pre>
*
* @see Humanize#spellDigit(Number, Locale)
*/
spellDigit {
@Override
public Object apply(final Object value, final Options options)
throws IOException {
isTrue(value instanceof Number, "found '%s', expected: 'number'", value);
return Humanize.spellDigit((Number) value, resolveLocale(options));
}
},
/**
* <p>
* Capitalize all the words, and replace some characters in the string to
* create a nice looking title.
* </p>
*
* <pre>
* {{titleize string}}
* </pre>
*
* @see Humanize#titleize(String)
*/
titleize {
@Override
public Object apply(final Object value, final Options options)
throws IOException {
isTrue(value instanceof String, "found '%s', expected: 'string'", value);
return Humanize.titleize((String) value);
}
},
/**
* <p>
* Strips diacritic marks.
* </p>
*
* <pre>
* {{transliterate string}}
* </pre>
*
* @see Humanize#transliterate(String)
*/
transliterate {
@Override
public Object apply(final Object value, final Options options)
throws IOException {
isTrue(value instanceof String, "found '%s', expected: 'string'", value);
return Humanize.transliterate((String) value);
}
},
/**
* <p>
* Makes a phrase underscored instead of spaced.
* </p>
*
* <pre>
* {{underscore string}}
* </pre>
*
* @see Humanize#underscore(String)
*/
underscore {
@Override
public Object apply(final Object value, final Options options)
throws IOException {
isTrue(value instanceof String, "found '%s', expected: 'string'", value);
return Humanize.underscore((String) value);
}
},
/**
* <p>
* Truncate a string to the closest word boundary after a number of
* characters.
* </p>
*
* <pre>
* {{wordWrap string length}}
* </pre>
*
* @see Humanize#wordWrap(String, int)
*/
wordWrap {
@Override
public Object apply(final Object value, final Options options)
throws IOException {
isTrue(value instanceof String, "found '%s', expected: 'string'", value);
Number length = options.param(0, null);
notNull(length, "found 'null', expected 'word wrap length'");
isTrue(length.intValue() > 0, "found '%s', expected 'a positive number'",
length);
return Humanize.wordWrap((String) value, length.intValue());
}
};
/**
* Resolve a locale.
*
* @param options The helper's options.
* @return A locale.
*/
protected static Locale resolveLocale(final Options options) {
String locale = options.hash("locale", Locale.getDefault().toString());
return Locales.fromString(locale);
}
/**
* Register all the humanize helpers.
*
* @param handlebars The helper's owner.
*/
public static void register(final Handlebars handlebars) {
notNull(handlebars, "A handlebars object is required.");
for (HumanizeHelper helper : values()) {
handlebars.registerHelper(helper.name(), helper);
}
}
}