package cuke4duke.internal.language; import cuke4duke.PyString; import cuke4duke.Scenario; import cuke4duke.internal.java.MethodInvoker; import cuke4duke.internal.jvmclass.CantTransform; import cuke4duke.internal.jvmclass.DefaultJvmTransforms; import cuke4duke.spi.ExceptionFactory; import cuke4duke.spi.jruby.StepMatch; import java.lang.reflect.Method; import java.util.*; public abstract class AbstractProgrammingLanguage implements ProgrammingLanguage { protected final LanguageMixin languageMixin; protected final MethodInvoker methodInvoker; private final ExceptionFactory exceptionFactory; private final Map<Class<?>, Method> transformMethods = new HashMap<Class<?>, Method>(); private List<StepDefinition> stepDefinitions; public AbstractProgrammingLanguage(LanguageMixin languageMixin, ExceptionFactory exceptionFactory) { this.languageMixin = languageMixin; this.exceptionFactory = exceptionFactory; this.methodInvoker = new MethodInvoker(this.exceptionFactory); for (Method method : DefaultJvmTransforms.class.getDeclaredMethods()) { transformMethods.put(method.getReturnType(), method); } } final public List<StepMatch> step_matches(String step_name, String formatted_step_name) throws Throwable { return step_match_list(step_name, formatted_step_name); } public abstract void load_code_file(String file) throws Throwable; public final List<StepMatch> step_match_list(String step_name, String formatted_step_name) throws Throwable { List<StepMatch> matches = new ArrayList<StepMatch>(); for (StepDefinition stepDefinition : stepDefinitions) { List<StepArgument> arguments = stepDefinition.arguments_from(step_name); if (arguments != null) { matches.add(languageMixin.create_step_match(stepDefinition, step_name, formatted_step_name, arguments)); } } return matches; } protected void clearHooksAndStepDefinitions() { languageMixin.clear_hooks(); stepDefinitions = new ArrayList<StepDefinition>(); } public void addBeforeHook(Hook before) { languageMixin.add_hook("before", before); } public void addStepDefinition(StepDefinition stepDefinition) { stepDefinitions.add(stepDefinition); } // This method is only used by JUnit public List<StepDefinition> getStepDefinitions() { return stepDefinitions; } public void addAfterHook(Hook after) { languageMixin.add_hook("after", after); } protected abstract void begin_scenario(Scenario scenario) throws Throwable; public abstract void end_scenario() throws Throwable; public void availableStepDefinition(String regexp_source, String file_colon_line) { languageMixin.available_step_definition(regexp_source, file_colon_line); } public void invoked(String regexp_source, String file_colon_line) { languageMixin.invoked_step_definition(regexp_source, file_colon_line); } protected Object[] transform(Object[] args, Class<?>[] parameterTypes, Locale locale) throws Throwable { Object[] transformed = new Object[args.length]; for (int i = 0; i < transformed.length; i++) { transformed[i] = transformOne(args[i], parameterTypes[i], locale); } return transformed; } public Object transformOne(Object arg, Class<?> parameterType, Locale locale) throws Throwable { if (PyString.class.isAssignableFrom(arg.getClass())) { arg = ((PyString) arg).to_s(); } if (parameterType.isAssignableFrom(arg.getClass())) { return arg; } Object customTransform = customTransform(arg, parameterType, null); if (customTransform != null) { return customTransform; } else { return defaultTransform(arg, parameterType, locale); } } private Object defaultTransform(Object arg, Class<?> parameterType, Locale locale) throws Throwable { Method transformMethod = transformMethods.get(parameterType); if (transformMethod == null) { throw new CantTransform(arg, parameterType); } return methodInvoker.invoke(transformMethod, null, new Object[]{arg, locale}); } protected abstract Object customTransform(Object arg, Class<?> parameterType, Locale locale) throws Throwable; public Exception cucumberArityMismatchError(String message) { return exceptionFactory.cucumberArityMismatchError(message); } public Exception cucumberPending(String message) { return exceptionFactory.cucumberPending(message); } public Exception error(String type, String message) { return exceptionFactory.error(type, message); } }