Ruby AOP in 12 lines of Code

First, we shim the Ruby Object class with a profiling aspect, in this case an additional method called profile that will wrap any existing method with timing code that we tell it to.

Lets put this in a file called: aop_extension.rb.

class Object

  def Object.profile symbol

    _symbol = ("rprof_" + symbol.to_s).to_sym

    alias_method _symbol, symbol

    # Define the new wrapper method 

    self.send(:define_method, symbol.to_s) { |*args|

      start_time = Time.now

      self.send(_symbol, *args)

      puts (Time.now - start_time).to_s + " have elapsed"

    }

    puts "The new method " + _symbol.to_s + " has been created for method " + symbol.to_s

  end

end

Now lets define a class that we can use as a test subject.  Create a file called greeter.rb.  Add the following:

 

require "./aop_extension.rb"

 

class Greeter

   def hello

    puts "hello"

  end

  profile :hello

end

Notice that in the constructor code we tell the inherited profile method to go after the “hello” method.  This creates a proxy method that will run the targeted method on behalf of callers.

Now lets see this thing in action.  For this we’ll create a file called main.rb.  Add the following:

require "./greeter.rb"

 

t = Greeter.new

t.hello

Finally, after all this extra heavy lifting we can see the goodness shining through in the output:

$ ruby main.rb
The new method rprof_hello has been created for method hello
hello
0.001 have elapsed

Wow, we didn’t even break a sweat on that one.

Property getter/setter extraction from C# Types

The C# Expression API allows you to scrape property and method definitions from Types and work with them as external references.  See here:



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Dynamic;
using System.Runtime.CompilerServices;

public static class Extensions

 {
       public static Func<X, T> GetPropertyFunction<X, T>(this Type source, string name)
          {
             ParameterExpression param = Expression.Parameter(typeof(X), "arg");
             MemberExpression member = Expression.Property(param, name);
             LambdaExpression lambda = Expression.Lambda(typeof(Func<X, T>), member, param);
             Func<X, T> compiled = (Func<X, T>)lambda.Compile();
             return compiled;
         }
}

 

And you can use it like this:


[TestMethod]
public void TestMethod1()
         {
             var testObj = new TestObject
             {
                 ID = 1,
                 Description = "ASDFASDF",
                 Name = "GGGG",
                 UnitPrice = 6
             };

             Type type = typeof(TestObject);
             var getName = type.GetPropertyFunction<TestObject, String>("Name");
             String value = getName(testObj);

             Assert.IsTrue(value == testObj.Name);
       }

My C# ObservableDictionary

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Collections.Specialized;

namespace DynamicSpikes
{
    public class ObservableDictionary<String, Object> : Dictionary<string, object>, INotifyPropertyChanged, INotifyCollectionChanged
    {

        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        public event NotifyCollectionChangedEventHandler CollectionChanged = delegate { };

        private void OnCollectionChanged(object sender, NotifyCollectionChangedAction action, object value)
        {
            if (CollectionChanged != null)
            {
                CollectionChanged(sender, new NotifyCollectionChangedEventArgs(action, value));
            }
        }

        private void OnPropertyChanged(object sender, string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public new void Add(string key, object value)
        {
            base.Add(key, value);
            OnCollectionChanged(this, NotifyCollectionChangedAction.Add, new KeyValuePair<string, object>(key, value));

            //OnPropertyChanged(this, "Values");
            //OnPropertyChanged(this, "Keys");
            //OnPropertyChanged(this, "Count");
        }

        public new bool Remove(string key)
        {
            var kvp = base[key];
            var result = base.Remove(key);
            if (result)
            {
                OnCollectionChanged(this, NotifyCollectionChangedAction.Remove, kvp);

                //OnPropertyChanged(this, "Values");
                //OnPropertyChanged(this, "Keys");
                //OnPropertyChanged(this, "Count");
            }
            return result;
        }

        public new object this[string key]
        {
            get
            {
                return base[key];
            }
            set
            {
                base[key] = value;
                PropertyChanged(this, new PropertyChangedEventArgs(key));
            }
        }
    }

}