001// Copyright 2012 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007// http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.tapestry5.internal.clojure;
016
017import clojure.lang.Symbol;
018import org.apache.tapestry5.clojure.MethodToFunctionSymbolMapper;
019
020import java.lang.reflect.Method;
021import java.util.regex.MatchResult;
022import java.util.regex.Matcher;
023import java.util.regex.Pattern;
024
025/**
026 * Default implementation that transforms a camelCased method-name to a clojure-style function name.
027 */
028public class DefaultMapper implements MethodToFunctionSymbolMapper
029{
030    @Override
031    public Symbol mapMethod(String namespace, Method method)
032    {
033        return mapMethodName(namespace, method.getName());
034    }
035
036    private Symbol mapMethodName(String namespace, String name)
037    {
038        return Symbol.create(namespace, transformName(name));
039    }
040
041    private final Pattern transition = Pattern.compile("(\\p{Lower}\\p{Upper})");
042
043    private String transformName(String name)
044    {
045
046        Matcher matcher = transition.matcher(name);
047
048        StringBuilder builder = new StringBuilder();
049
050        int lastx = 0;
051
052        while (matcher.find())
053        {
054            MatchResult matchResult = matcher.toMatchResult();
055
056            int start = matchResult.start();
057            int end = matchResult.end();
058
059            builder.append(name.substring(lastx, start + 1));
060            builder.append('-');
061            // TODO: An acronym (such as "URL") should not be lower cased here.
062            builder.append(name.substring(end - 1, end).toLowerCase());
063
064            lastx = end;
065        }
066
067        if (lastx == 0)
068        {
069            return name;
070        }
071
072        builder.append(name.substring(lastx));
073
074        return builder.toString();
075    }
076
077}