CS 330 Lecture 38 – Reflection and Metaprogramming
Agenda
- what ?s
- a testing framework in Ruby
- checking for correct overrides in Java
- handling wild calls in Ruby
Code
Certain.rb
#!/usr/bin/env ruby
module Certain
def self.assert_equals fail_message, expected, actual
if expected != actual
puts fail_message
end
end
def self.run suite
instance = suite.new
instance.methods.grep /^test_/ do |test|
instance.send test
end
# puts 'All tests pass'
end
end
class Vector2
def initialize x, y
@x = x
@y = y
end
def x
@x
end
def y
@y
end
def length
Math.sqrt(@x * @x + @y * @y)
end
def normalize
l = length
@x /= l
@y /= l
self
end
def == other
(x - other.x).abs < 0.00001 and (y - other.y).abs < 0.00001
end
def to_s
"(#{x},#{y})"
end
end
class TestVector2
def test_subscript
v = Vector2.new 5, 7
Certain.assert_equals "Vector2.x yields incorrect x", 5, v.x
Certain.assert_equals "Vector2.y yields incorrect y", 7, v.y
end
def test_length
v = Vector2.new 3, 4
Certain.assert_equals "Vector2.length wrong", 5, v.length
end
def test_normalize
v = Vector2.new 10, 0
Certain.assert_equals "Vector2.normalize computes bad vector", Vector2.new(1, 0), v.normalize
v = Vector2.new 3, 4
Certain.assert_equals "Vector2.normalize computes bad vector", Vector2.new(0.6, 0.8), v.normalize
end
end
Certain.run TestVector2
Usurps.java
package cs330_egs;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Usurps {
}
Supertype.java
package cs330_egs;
public class Supertype {
public Integer get(String s) {
return 0;
}
}
Subtype.java
package cs330_egs;
public class Subtype {
@Usurps
public Object get(String s) {
return 0;
}
public void foo() {
}
}
UsurpsCheck.java
package cs330_egs;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
public class UsurpsCheck {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> subclass = Class.forName("cs330_egs.Subtype");
// subclass.getSuperclass()
Class<?> superclass = Class.forName("cs330_egs.Supertype");
List<Method> subMethods = Arrays.asList(subclass.getDeclaredMethods());
// System.out.println(subMethods);
subMethods.stream().forEach(subMethod -> {
Usurps annotation = subMethod.getAnnotation(Usurps.class);
if (annotation != null) {
// we know that this method is supposed to usurper!
try {
Method superMethod = superclass.getMethod(subMethod.getName(), subMethod.getParameterTypes());
if (!superMethod.getReturnType().isAssignableFrom(subMethod.getReturnType())) {
System.err.println(subMethod.getName() + " says it usurps, but doesn't have a covariant return type! Wah!");
System.err.println(subMethod.getReturnType() + " must be <= " + superMethod.getReturnType());
}
} catch (Exception e) {
System.err.println(subMethod.getName() + " has nothing to usurp!");
}
}
});
}
}
weather.json
{"coord":{"lon":-91.5,"lat":44.82},"message":0.0355,"country":"United States of America","sunrise":1399286929,"sunset":1399338988,"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}],"base":"cmc stations","main":{"temp":281.88,"humidity":60,"pressure":1014,"temp_min":280.93,"temp_max":282.15},"wind":{"speed":2.57,"gust":5.65,"deg":87},"rain":{"3h":0},"clouds":{"all":92},"dt":1399287329,"id":5251436,"name":"Eau Claire","cod":200}
ezserial.rb
#!/usr/bin/env ruby
require 'json'
class Zerial
def initialize path
@contents = JSON.load(IO.read(path))
end
def method_missing name, *args
if args.length == 0 and @contents.has_key? name.to_s
@contents[name.to_s]
elsif args.length == 1 and name[-1] == '='
@contents[name.to_s[0...-1]] = args[0]
puts @contents
else
super
end
end
def to_s
@contents.to_s
end
end
o = Zerial.new 'weather.json'
puts Time.at(o.sunset)
o.sunrise = 6
Haiku
I look at myself
What am I capable of?
What am I capable of?
***Segmentation fault***