Skip to content

Commit

Permalink
Merge pull request ReactiveX#2 from benjchristensen/static-core
Browse files Browse the repository at this point in the history
Groovy, Statics, Fixes
  • Loading branch information
mattrjacobs committed Aug 29, 2013
2 parents 704d4e3 + 4b441ba commit 0237f1e
Show file tree
Hide file tree
Showing 29 changed files with 1,243 additions and 2,159 deletions.
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,7 @@ subprojects {
}
}

project(':rxjava-core') {
sourceSets.test.java.srcDir 'src/test/java'
}

2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version=0.10.2
version=0.11.0-SNAPSHOT
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
(ns rx.lang.clojure.DummyClojureClass)

(defn hello-world [username]
(println (format "Hello, %s" username)))

(hello-world "world")
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* Copyright 2013 Netflix, Inc.
*
* 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 rx.lang.groovy;

import groovy.lang.Closure;
import rx.util.functions.Action;
import rx.util.functions.Action0;
import rx.util.functions.Action1;
import rx.util.functions.Action2;
import rx.util.functions.Action3;

/**
* Concrete wrapper that accepts a {@link Closure} and produces any needed Rx {@link Action}.
*
* @param <T1>
* @param <T2>
* @param <T3>
* @param <T4>
*/
public class GroovyActionWrapper<T1, T2, T3, T4> implements Action, Action0, Action1<T1>, Action2<T1, T2>, Action3<T1, T2, T3> {

private final Closure<Void> closure;

public GroovyActionWrapper(Closure<Void> closure) {
this.closure = closure;
}

@Override
public void call() {
closure.call();
}

@Override
public void call(T1 t1) {
closure.call(t1);
}

@Override
public void call(T1 t1, T2 t2) {
closure.call(t1, t2);
}

@Override
public void call(T1 t1, T2 t2, T3 t3) {
closure.call(t1, t2, t3);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* Copyright 2013 Netflix, Inc.
*
* 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 rx.lang.groovy;

import groovy.lang.Closure;
import rx.util.functions.Func0;
import rx.util.functions.Func1;
import rx.util.functions.Func2;
import rx.util.functions.Func3;
import rx.util.functions.Func4;
import rx.util.functions.Function;

/**
* Concrete wrapper that accepts a {@link Closure} and produces any needed Rx {@link Function}.
*
* @param <T1>
* @param <T2>
* @param <T3>
* @param <T4>
* @param <R>
*/
public class GroovyFunctionWrapper<T1, T2, T3, T4, R> implements Func0<R>, Func1<T1, R>, Func2<T1, T2, R>, Func3<T1, T2, T3, R>, Func4<T1, T2, T3, T4, R> {

private final Closure<R> closure;


public GroovyFunctionWrapper(Closure<R> closure) {
this.closure = closure;
}

@Override
public R call() {
return (R) closure.call();
}

@Override
public R call(T1 t1) {
return (R) closure.call(t1);
}

@Override
public R call(T1 t1, T2 t2) {
return (R) closure.call(t1, t2);
}

@Override
public R call(T1 t1, T2 t2, T3 t3) {
return (R) closure.call(t1, t2, t3);
}

@Override
public R call(T1 t1, T2 t2, T3 t3, T4 t4) {
return (R) closure.call(t1, t2, t3, t4);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/**
* Copyright 2013 Netflix, Inc.
*
* 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 rx.lang.groovy;

import groovy.lang.Closure;
import groovy.lang.GroovySystem;
import groovy.lang.MetaMethod;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.codehaus.groovy.reflection.CachedClass;
import org.codehaus.groovy.reflection.ReflectionCache;
import org.codehaus.groovy.runtime.m12n.ExtensionModule;
import org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl;

import rx.Observable;
import rx.observables.BlockingObservable;
import rx.util.functions.Action;
import rx.util.functions.Function;

/**
* ExtensionModule that adds extension methods to support groovy.lang.Closure
* anywhere rx.util.functions.Function/Action is used in classes defined in CLASS_TO_EXTEND.
*
* It is specifically intended for providing extension methods on Observable.
*/
public class RxGroovyExtensionModule extends ExtensionModule {

@SuppressWarnings("rawtypes")
private final static Class[] CLASS_TO_EXTEND = new Class[] { Observable.class, BlockingObservable.class };

public RxGroovyExtensionModule() {
super("RxGroovyExtensionModule", "1.0");
}

/**
* Keeping this code around a little while as it was hard to figure out ... and I'm still messing with it while debugging.
*
* Once the rest of this ExtensionModule stuff is working I'll delete this method.
*
* This is used for manually initializing rather than going via the org.codehaus.groovy.runtime.ExtensionModule properties file.
*/
public static void initializeManuallyForTesting() {
System.out.println("initialize");
MetaClassRegistryImpl mcRegistry = ((MetaClassRegistryImpl) GroovySystem.getMetaClassRegistry());
// RxGroovyExtensionModule em = new RxGroovyExtensionModule();

Properties p = new Properties();
p.setProperty("moduleFactory", "rx.lang.groovy.RxGroovyPropertiesModuleFactory");
Map<CachedClass, List<MetaMethod>> metaMethods = new HashMap<CachedClass, List<MetaMethod>>();
mcRegistry.registerExtensionModuleFromProperties(p, RxGroovyExtensionModule.class.getClassLoader(), metaMethods);

for (ExtensionModule m : mcRegistry.getModuleRegistry().getModules()) {
System.out.println("Module: " + m.getName());
}

for (CachedClass cc : metaMethods.keySet()) {
System.out.println("Adding MetaMethods to CachedClass: " + cc);
cc.addNewMopMethods(metaMethods.get(cc));
}
}

@SuppressWarnings("rawtypes")
@Override
public List<MetaMethod> getMetaMethods() {
// System.out.println("**** RxGroovyExtensionModule => Initializing and returning MetaMethods.");
List<MetaMethod> methods = new ArrayList<MetaMethod>();

for (Class classToExtend : CLASS_TO_EXTEND) {
for (final Method m : classToExtend.getMethods()) {
for (Class c : m.getParameterTypes()) {
if (Function.class.isAssignableFrom(c)) {
methods.add(createMetaMethod(m));
// break out of parameter-type loop
break;
}
}
}
}

return methods;
}

private MetaMethod createMetaMethod(final Method m) {
return new MetaMethod() {

@Override
public int getModifiers() {
return m.getModifiers();
}

@Override
public String getName() {
return m.getName();
}

@SuppressWarnings("rawtypes")
@Override
public Class getReturnType() {
return m.getReturnType();
}

@Override
public CachedClass getDeclaringClass() {
return ReflectionCache.getCachedClass(m.getDeclaringClass());
}

@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Object invoke(Object object, Object[] arguments) {
// System.out.println("***** RxGroovyExtensionModule => invoked [" + getName() + "]: " + object + " args: " + arguments[0]);
try {
Object[] newArgs = new Object[arguments.length];
for (int i = 0; i < arguments.length; i++) {
final Object o = arguments[i];
if (o instanceof Closure) {
if (Action.class.isAssignableFrom(m.getParameterTypes()[i])) {
newArgs[i] = new GroovyActionWrapper((Closure) o);
} else {
newArgs[i] = new GroovyFunctionWrapper((Closure) o);
}

} else {
newArgs[i] = o;
}
}
return m.invoke(object, newArgs);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof RuntimeException) {
// re-throw whatever was thrown to us
throw (RuntimeException) e.getCause();
} else {
throw new RuntimeException(e);
}
}
}

@SuppressWarnings("rawtypes")
@Override
public CachedClass[] getParameterTypes() {
Class[] pts = m.getParameterTypes();
CachedClass[] cc = new CachedClass[pts.length];
for (int i = 0; i < pts.length; i++) {
if (Function.class.isAssignableFrom(pts[i])) {
// function type to be replaced by closure
cc[i] = ReflectionCache.getCachedClass(Closure.class);
} else {
// non-function type
cc[i] = ReflectionCache.getCachedClass(pts[i]);
}
}
return cc;
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Copyright 2013 Netflix, Inc.
*
* 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 rx.lang.groovy;

import java.util.Properties;

import org.codehaus.groovy.runtime.m12n.ExtensionModule;
import org.codehaus.groovy.runtime.m12n.PropertiesModuleFactory;

/**
* Factory for {@link RxGroovyExtensionModule} to add extension methods.
* <p>
* This is loaded from /META-INF/services/org.codehaus.groovy.runtime.ExtensionModule
* <p>
* The property is defined as: moduleFactory=rx.lang.groovy.RxGroovyPropertiesModuleFactory
*/
public class RxGroovyPropertiesModuleFactory extends PropertiesModuleFactory {

@Override
public ExtensionModule newModule(Properties properties, ClassLoader classLoader) {
return new RxGroovyExtensionModule();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
moduleFactory=rx.lang.groovy.RxGroovyPropertiesModuleFactory
Loading

0 comments on commit 0237f1e

Please sign in to comment.