Archive for the 'Ruby' Category

19AugIronNails: Some progress

I thought it might be a good idea to update you guys on how IronNails is progressing.  I think I’ve got it so that you aren’t exposed to writing many of the boring boilerplate code that comes with taking this approach (M – V – VM- C). Also to execute an action on a controller asynchronously you can by just adding :mode => :asynchronous to your view_action declaration.

A lot is still left to do but this proves that it is possible to use IronRuby today to do some pretty cool stuff. From the top of my head here are some things that still need to be done:

  • The ability to load xaml from an assembly like the one that is generated when you use Blend for your design.
  • More predefined behaviors
  • Templated generators
  • Silverlight support

But the core of the framework is working. Now it’s a matter of extending the functionality. Some of the features the framework does support

  • Binding to controller actions through commands
  • Binding to controller actions through event handlers on the view proxy
  • Asynchronous execution of actions
  • Timed execution of actions
  • Binding to models

I will be developing my sample for my chapter against this framework and will add the pieces I’m missing as I get on.

Some of the things I foresee that might need to be added are:

  • support for controlling the application from an IronRuby console so that you can interact with the interface as it is running.
  • support for a console to interact with the code of the application.
  • support for plugins

So after all these lists how would an application look like when you are developing it?

The controller:

# file name: demo_controller.rb
class DemoController < IronNails::Controller::Base
  view_object :status_bar_message, "The status bar message"

  view_action :change_message

  def change_message
    @status_bar_message = "#@status_bar_message appended"
  end
end

The ViewModel:

# file name: DemoViewModel.cs
public class DemoViewModel : IronNails.View.ViewModel { }

The View:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:behaviors="clr-namespace:IronNails.Library.Behaviors;assembly=IronNails.Library"
    Title="Window1" Height="300" Width="300">
    <StackPanel>
        <TextBlock Text="{Binding Objects[StatusBarMessage].Value}" ></TextBlock>
        <Button Content="Click me" behaviors:ClickBehavior.LeftClick="{Binding Commands[ChangeMessage]}" />
    </StackPanel>
</Window>

There are currently 2 dictionaries available to the view. One that contains the models (Objects) and one that contains the commands (Commands).  The value of an entry in the Objects needs to be observable by implementing INotifyPropertyChanged and that is what’s responsible for the binding syntax Objects[ModelName].Value

At this moment there are only a couple of behaviors implemented: LeftClick, RightClick, DoubleClick and Hover.

The framework expects that you follow the basic naming conventions of the technology you’re programming in. So in ruby you underscore names but in C# and xaml you camelcase them.

By defining an object with view_object :o bject_name, default value you define it with a default value that you can change afterwards in the controller actions.  By defining an action with view_action :action_name, :mode => :asynchronous you tell that framework that you want to link a method or a block as a controller action and execute it asynchronously.

07AugIronNails : Rails like development for IronRuby with WPF/Silverlight

For my book IronRuby I’m working on chapter 4. That chapter is about doing WPF development with IronRuby. I started out with a straight port of Witty to IronRuby. As I was doing that the cogs started turning and I came up with a way to bring the rails style of development to WPF.   I decided to investigate that route a little bit further and now I have a small framework that enables you to write WPF applications with the MVC paradigm. I decided to open that code up as open source and host it on github. 

At first I used the name Sails for my framework but it turns out there is java clone of rails that is called opensails. So to avoid confusion David M. Peterson proposed the name IronNails.

On Sat, 02 Aug 2008 08:00:44 -0600, Charles Oliver Nutter wrote:

    FYI, there’s already a framework named "Sails" for Java:
http://www.opensails.org/

For the sake of sticking to the "Iron" theme, why not replace the ‘S’ with an ‘N’ and go with IronNails. ;-)   Maybed it’s just me, but if given the choice, I’d much rather nail it than sail it any day of the week. :D


/M:D

M. David Peterson

You can find the project here: http://github.com/casualjim/ironnails

At this moment it’s definitely not finished at all, but it does work. The remainder of the week I’ll move my previous demo code onto this framework, update the code samples in my chapter and finish the content. I hope I will have all of this done by the end of next week.

Back to the IronNails project:

Because DLR objects cannot be used to bind to in WPF you have to define a skeleton of the ViewModel in C#, but this will change in the future. When that changes I’ll look at extending the framework to make use of some other WPF patterns like defining a DependencyObject and Behaviors. Once those are defined you get a very clean separation between design and behavior.

This is abstracted away from you but in the background the framework works with the View – ViewModel – Model – Controller pattern although I’ve tried to keep your exposure to the view model to a minimum. The framework follows naming conventions per language. So in C# and XAML you camel case stuff and in IronRuby you underscore stuff.

The very core of the framework is defined in C# but most of the code is IronRuby, depending on how hard it will be after the DLR RTM’s I may look at adding support for all the DLR languages.

IronNails
=========

IronNails is a framework inspired by the Rails and rucola frameworks. It offers a rails-like way of developing
applications with IronRuby and Windows Presentation Foundation (WPF).
This framework uses the pattern Model – ViewModel – View – Controller (M-VM-V-C). It should be able to run on both WPF
and Silverlight.
The idea is that the views can be created using a design tool like Blend for example and just save that xaml as is. The
designer should not need to use anything else than drag and drop to create a GUI design. The behaviors are then added to
the view by using predefined behaviors in the framework or by defining your own behavior.
The framework then generates a proxy for the view which will be used to transparently wire up the commands in the
behaviors to controller actions.

You are now able to write the following code for a controller:

class MyController < IronNails::Controller::Base

  view_action :show_message, :triggers => :my_button do
    MessageBox.show "This is the great message from a block"
  end

  view_action :change_color, :triggers => { :element => :my_text_block, :event => :mouse_enter }
  view_action :reset_color, :triggers => { :element => :my_text_block, :event => :mouse_leave } do |view|
    view.my_text_block.foreground = :black.to_brush
  end

  view_object :people, Person.find_all

  def change_color(view)
    view.my_text_block.foreground = :red.to_brush
  end

end

At this moment the project has 0 unit tests, it has below minimal documentation and it still needs a work like defining the behaviors. I have to move on with my book but intend to continue developing this framework after my book is finished and IronRuby RTM’s.  There are some more workarounds in the project that will all disappear as IronRuby progresses.

kick it on DotNetKicks.com

09AprUpdated my lightspeed model generator

This week I could start a project that has a database that goes somewhat beyond a blog. This seemed to me like the best way to improve my model generator that I built earlier

And as expected I needed to tweak it a little so that it would work properly, and I added a feature.

Seen as there are 2 files generated for an entity if you add a private field that exists in the database there then the generator will skip it so that you can add more attributes than the ones this script generates for you. If you override a field you also have to put the property in the user file.

I also added support for generating a datacontext. If you want to use the Linq support that Lightspeed is getting then that is a starting point. The same goes for this class with user files and generated file as above, the user file takes precedence.

I hosted this project on google code so you can check it out from there. Or you can download todays version

del.icio.us Tags: ,,

Technorati Tags: ,,

kick it on DotNetKicks.com

09FebUsing Ruby to Generate LightSpeed Models – Part 4

UPDATE: I have an update here with a new version and the location on google code where the project is hosted now.

 

In the previous 3 parts (part 1, part 2, part 3) we talked about getting the meta data out of the database and generating the lightspeed entities in memory.

I won’t put the code listings up in this blog post but instead will give you a link to the complete code :) You can download the express edition of LightSpeed and try it for yourself if you want.

Instead I’ll talk about how you can use the ruby script to generate the models from an existing database.

It adds the generated files to the visual studio project file in the same directory or you can specify one.

Currently it only supports Sql Server 2005. You need to create a project first in visual studio so we have

a project file to add items to.

To use it you have to tell it which database it has to find by putting a database.yml file in your visual studio project directory.

The content of that database.yml file may look as follows

# on windows you can use the following connection string

#

# sqlserver:

#   database: northwind

#   host: localhost

#   username: sa

#   password: MaybePassword123

# on OSX and Linux you can connect to sql server through odbc (iODBC or unixODBC in combination with FreeTDS)

#

# sqlserver:

#   dsn: NorthwindSql

#   username: sa

#   password: MaybePassword123

when you’ve done that you can execute it like shown in the screenshot below:

Terminal-screenshot

I have a database.yml file in the directory and I execute the command ruby < >

on linux and OSX you can chmod +x that path and then you don’t have to type ruby anymore.

That will generate the models for your database provided that your database conforms to the conventions needed for LightSpeed.

The next step would be to open visuals studio and build the project. The files got added in visual studio every entity are 2 files one with the generated code and one empty one that you can use to implement behavior on the model if you would want to.

The first picture shows how the solution explorer looks and the second one shows the results of the build without having touched one file after generation.

In the download there is a folder db which contains a slightly modified script from the Northwind database that comes with the samples for lightspeed. I used that database because it has every type of relationship and the script did conform to the lightspeed conventions :)

LightSpeedGenerateTest

LightSpeedGenerateTestBuildResult

del.icio.us Tags: ,,

Technorati Tags: ,,

kick it on DotNetKicks.com

05FebUsing Ruby to Generate LightSpeed Models – Part 3

First off I’m writing with windows live writer again, ecto wasn’t up to the job. It tried to “clean” my html, granted it was messy but it should leave my text untouched. The whole editing experience wasn’t satisfying enough. And Ecto already seemed like the best blog editor for mac, slim pickings indeed. From my tools I expect foremost that they stay out of my way and it didn’t. I just talked with Simone about looking at making a .NET based client that runs on mono, we’ll see where that plan goes because I don’t really have time to do that for the moment.

In the previous posts in this series (part 1, part 2) we discovered how to connect to the database and how to get the meta data about that database out. Maybe I should also explain why I’m doing this series with LightSpeed instead of ActiveRecord from Castle or SubSonic or Linq2Sql for that matter. I will definitely touch on all those orms in the coming week, but I started with LightSpeed because it’s the easiest ORM I’ve ever used.

This post will deal with actually doing something useful with that meta data. Today we’re going to generate the represenation of the entities and their properties. Tomorrow we’ll deal with actually generating the files from the the in-memory presentation we’re generating today.

We’re going to need 2 classes in addition to the LightSpeedRepository class. One to represent an entity and one to represent a property. The goal is for tomorrow to render the entities as complete as possible with validation attributes etc.

And without further ado here are the specs we’re going to build:

LightSpeedRepository Conversion
- should convert a given table to light speed metadata
- should convert a given table without relations to a light speed entity definition
- should convert a given table with a m:1 relation to a light speed entity definition
- should convert a given table with a 1:m relation to a light speed entity definition
- should convert a given table with a m:n relation to a light speed entity definition

LightSpeedProperty
- should allow for a property to be set
- should return a predicate for booleans
- should return a predicate for booleans
- should return a sql type
- should be a lightSpeed property

LightSpeedEntity
- should have properties, has many, belongs to and through associations
- should create a valid property name if one doesn’t exists already in the through association properties
- should create a valid property name if one doesn’t exists already in the has many properties
- should create a valid property name if one doesn’t exists already in the belongs to properties
- should create a valid property name if one doesn’t exists already in the properties
- should create a valid property name if one already exists in the through association properties
- should create a valid property name if one already exists in the has many properties
- should create a valid property name if one already exists in the belongs to properties
- should create a valid property name if one already exists in the properties
- should create a valid property name if two already exist in the through association properties
- should create a valid property name if two already exist in the has many properties
- should create a valid property name if two already exist in the belongs to properties
- should create a valid property name if two already exist in the properties

Let’s start with looking at the LightSpeedProperty first. The attributes on this class are implemented using some simple metaprogramming. This class will represent a field in a LightSpeed entity and will take care of rendering that properly into the c# file. We actually create the data in the LightSpeedRepository class.

class LightSpeedProperty

  attr_accessor :attributes

  def initialize(params = {})
    @attributes = params
    LightSpeedProperty.create_methods params

  end

  def [](attribute)
    attributes[attribute]
  end

  def self.create_methods(params)

    params.each do |k, v|
      define_method("#{k}=") do |val|
        @attributes[k]= val
      end

      predicate = %w(primary_key foreign_key unique nullable).any? { |o| o === k.to_s }

      define_method(predicate ? "#{k}?" : "#{k}") do
        @attributes[k]
      end

    end
  end

end

In the LightSpeed entity class we describe the actual Entity. I monkey patched Array so that I could ask it the question if it has a particular property. To avoid naming conflicts we check for properties that exist already and otherwise give them a generic new name by appending a number.

class Array

  def has_property?(name)
    exists = false

    each do |hm|
      exists = hm[:name] == name
      break if exists
    end

    exists
  end
end

class LightSpeedEntity
  attr_accessor :properties, :belongs_to, :has_many, :through_associations, :name, :namespace

  def initialize
    @properties = []
    @belongs_to = []
    @has_many = []
    @through_associations =[]
  end

  def create_property_name_from(from, idx=0)
    tname = build_property_name_from from, idx
    idx += 1 #when the property exists try with a higher number
    return create_property_name_from(from, idx) if has_property?(tname)
    tname
  end

  private

    def has_property?(tname)
      properties.has_property? tname or has_many.has_property? tname or belongs_to.has_property? tname or through_associations.has_property? tname
    end

    def build_property_name_from(from, idx)
      if idx == 0
        from
      else
        "#{from}#{idx}"
      end
    end

end

And this brings us to our last class of today the Repository class. We mixin the DB::MetaData module we created yesterday. Define a read_only property entities, make sure we can set a namespace for our generated entities. The first step is to transform the meta data into data that we can use to represent a LightSpeed Entity. The second and last step of today is to generate the entities with the lightspeed meta data. We have to skip the primary key because that is defined by convention in LightSpeed.

class LightSpeedRepository

  include DB::MetaData

  attr_reader :entities
  attr_accessor :namespace

  def initialize()
    @entities = []
    super
  end

  def to_light_speed_meta_data
    tables.collect do |table|
      col_infos = column_info_for table[:name]

      field_infos = col_infos.collect do |col_info|
        {
          :name => col_info[:name].underscore,
          :sql_type => col_info[:sql_type],
          :max_length => col_info[:max_length].to_i,
          :nullable => !col_info[:is_nullable].to_i.zero?,
          :precision => col_info[:precision],
          :foreign_key => foreign_key?(col_info),
          :primary_key => primary_key?(col_info),
          :unique => !col_info[:is_unique].to_i.zero?
        }
      end

      { :table_name => table[:name], :class_name => table[:name].singularize.camelize, :fields => field_infos }
    end
  end

  def generate_entities
    meta_data = to_light_speed_meta_data
    meta_data.each do |md|
      @entities << generate_entity(md)
    end
    @entities
  end

  def generate_entity(meta_data)
    entity = LightSpeedEntity.new
    entity.name = meta_data[:class_name]
    entity.namespace = namespace

    meta_data[:fields].each do |fi|
      prop = LightSpeedProperty.new(fi)

      prop.name = entity.create_property_name_from prop.name.underscore.camelize
      entity.properties << prop unless prop.primary_key?
      entity.belongs_to << generate_belongs_to_relation(meta_data, fi, entity) if prop.foreign_key?

    end

    entity.has_many = generate_has_many_relations meta_data, entity
    generate_through_associations meta_data, entity

    entity
  end

  private

    def generate_belongs_to_relation(meta_data, field_info, entity)
      {
        :name => entity.create_property_name_from(field_info[:name].underscore.humanize.titleize.gsub(/\s/,'')),
        :class_name => get_belongs_to_table(meta_data[:table_name], field_info[:name]).underscore.camelize.singularize
      }
    end

    def generate_has_many_relations(meta_data, entity)
      hms = collect_has_many_relations meta_data[:table_name]
      hms.collect do |hm|
         hm[:name] = entity.create_property_name_from hm[:class_name].pluralize
         hm
      end

    end

    def generate_through_associations(meta_data, entity)
      tas = collect_through_associations(meta_data[:table_name])
      tas.each do |ta|
        ta[:end_tables].each do |et|
          entity.through_associations << {
            :through => ta[:through_table].classify.singularize,
            :class_name => et.camelize.singularize,
            :name => entity.create_property_name_from(et.camelize)
          }
        end
      end
    end
end

Technorati Tags: ,,

del.icio.us Tags: ,,

05FebUsing Ruby to Generate LightSpeed models – Part 2

This is the second post in the series on generating LightSpeed entities with the help from ruby.
In the previous post we connected successfully to the database and were able to execute some sql.

At the end of the series I’ll make the code downloadable.

Today I’d like to talk about the metadata we’ll be needing from the database. We’re going to need a list of tables, we’re going to need to know about the columns of each table. Furthermore we want to exclude the primary keys in the case of LightSpeed. And we also want to know about relationships whether they are has many, belongs to or has many and belongs to many.

I put all this in a separate module because I’ll probably need that meta data for another thing later :) . The above requirements translate in the following spec:

LightSpeedRepository DB::MetaData
- should have meta data
- should resolve the table name from a string
- should resolve the table name from a hash
- should identify a given column as not being a foreign key
- should identify a foreign key given a valid column info
- should not identify a given column as being a primary key
- should identify a given column as being a primary key
- should not identify a table as a join table under the correct conditions
- should identify a table as a join table under the correct conditions
- should return an empty array of has many relations when there are none
- should return the has many relations given a table
- should return the end point tables for a given through association
- should return the through associations

The first thing we’re going to need are the sql statements. At this point I only need the statements for sql 2005 so and these are the ones I used.

def self.sql_statements
      {
        :tables => "SELECT table_name as name FROM information_schema.Tables Where table_type='Base Table' ORDER BY table_name",
        :column_info => "select object_name(c.object_id) as table_name, c.column_id, c.name, type_name(system_type_id) as sql_type, max_length, is_nullable, precision, scale,
              convert(bit,(Select COUNT(*) from sys.indexes as i
                inner join sys.index_columns as ic
                  on ic.index_id = i.index_id and ic.object_id = i.object_id
                inner join sys.columns as c2 on ic.column_id = c2.column_id and i.object_id = c2.object_id
              WHERE i.is_primary_key = 0
                and i.is_unique_constraint = 0 and ic.column_id = c.column_id and i.object_id=c.object_id)) as is_index,
              is_identity,
              is_computed,
              convert(bit,(Select Count(*) from sys.indexes as i inner join sys.index_columns as ic
                  on ic.index_id = i.index_id and ic.object_id = i.object_id
                inner join sys.columns as c2 on ic.column_id = c2.column_id and i.object_id = c2.object_id
              WHERE (i.is_unique_constraint = 1) and ic.column_id = c.column_id and i.object_id=c.object_id)) as is_unique
              from sys.columns as c
              WHERE object_name(c.object_id)  in (select table_name	FROM information_schema.Tables WHERE table_type = 'Base Table')
              order by table_name",
        :primary_keys => "SELECT i.name AS index_name,ic.index_column_id,key_ordinal,c.name AS column_name,TYPE_NAME(c.user_type_id)AS column_type
                    ,is_identity,OBJECT_NAME(i.object_id) as table_name FROM sys.indexes AS i INNER JOIN sys.index_columns AS ic ON
                    i.object_id = ic.object_id AND i.index_id = ic.index_id INNER JOIN sys.columns AS c ON ic.object_id = c.object_id
                    AND c.column_id = ic.column_id WHERE i.is_primary_key = 1 order by table_name",
        :foreign_keys => "SELECT f.name AS foreign_key_name, object_name(f.parent_object_id) AS table_name , col_name(fc.parent_object_id, fc.parent_column_id) AS child_id
                    ,object_name (f.referenced_object_id) AS parent_table ,col_name(fc.referenced_object_id, fc.referenced_column_id) AS parent_id FROM sys.foreign_keys AS f
                    INNER JOIN sys.foreign_key_columns AS fc ON f.object_id = fc.constraint_object_id where OBJECT_NAME(f.parent_object_id) not in ('sysdiagrams')  order by table_name"
       }
     end

Those statements contain all the data we need an probably a little bit more too, if we add a little metaprogramming we can have ruby generate that metadata data for us :)

    def populate
      DB::MetaData.sql_statements.each do |key, value|
        instance_variable_set("@"+key.to_s, @db.fetch_all(value))
      end
    end

    sql_statements.each_key do |key|
       define_method("#{key}_for") do |table|
         send(key, table).select { |item| item[:table_name] == table_name(table) }
       end unless key == :tables
     end

So now we’ve satisfied our first spec the module now contains all the meta data we need. The rest of the specs require far less code than what we wrote here. Below you’ll find the code needed to satisfy all of the specs. It are just a couple of methods that check some conditions and a couple of predicates we’re going to need later on. The get_endpoint_tables method is the only one that doesn’t explain itself easily. That method returns the table names from tables that are the second level in a has many and belongs to many scenario.

module DB
  module MetaData
    attr_accessor :tables, :primary_keys, :foreign_keys, :column_info

    def initialize
      @db = DB::DbiSqlServer.new
      populate
    end

    def populate
      DB::MetaData.sql_statements.each do |key, value|
        instance_variable_set("@"+key.to_s, @db.fetch_all(value))
      end
    end

    def collect_has_many_relations(table)
      fks = foreign_keys.select { |fk| fk[:parent_table] ==  table_name(table)  }

      fks.collect  do |fk|
        unless fk[:table_name].nil?
          { :table_name => fk[:table_name].underscore, :class_name => fk[:table_name].singularize.underscore.camelize }
        end
       end.compact
    end

    def collect_through_associations(table)
      fks = foreign_keys.select { |fk| fk[:parent_table] ==  table_name(table)  }

      fks.collect do |fk|
          { :through_table => fk[:table_name].underscore, :end_tables => get_endpoint_tables(table, fk[:table_name]) } if join_table?(fk[:table_name])
      end.compact
    end

    def get_endpoint_tables(table, through_table)
      fks = foreign_keys.select { |fk| fk[:table_name] == table_name(through_table) and fk[:parent_table] != table_name(table)  }
      fks.collect { |fk| fk[:parent_table].underscore unless fk[:parent_table].nil?  }.compact
    end

    def get_belongs_to_table(table, column_name)
      fks = foreign_keys.select { |fk|  fk[:table_name] == table_name(table) and fk[:child_id] = column_name }
      return fks[0][:parent_table] if fks.size > 0
      nil
    end

    def join_table?(table)
      fks = foreign_keys_for table_name(table)
      fks.size > 1
    end

    def primary_key?(column_info)
      pks = primary_keys.select { |pk| pk[:table_name] == column_info[:table_name] and pk[:column_name] == column_info[:name]   }

      pks.size > 0
    end

    def foreign_key?(column_info)
      fks = foreign_keys.select { |fk| fk[:table_name] == column_info[:table_name] and fk[:child_id] == column_info[:name]  }
      fks.size > 0
    end

    def table_name(table)
      table.is_a?(Hash) ? table[:name] : table
    end

    def self.sql_statements
      {
        :tables => "SELECT table_name as name FROM information_schema.Tables Where table_type='Base Table' ORDER BY table_name",
        :column_info => "select object_name(c.object_id) as table_name, c.column_id, c.name, type_name(system_type_id) as sql_type, max_length, is_nullable, precision, scale,
              convert(bit,(Select COUNT(*) from sys.indexes as i
                inner join sys.index_columns as ic
                  on ic.index_id = i.index_id and ic.object_id = i.object_id
                inner join sys.columns as c2 on ic.column_id = c2.column_id and i.object_id = c2.object_id
              WHERE i.is_primary_key = 0
                and i.is_unique_constraint = 0 and ic.column_id = c.column_id and i.object_id=c.object_id)) as is_index,
              is_identity,
              is_computed,
              convert(bit,(Select Count(*) from sys.indexes as i inner join sys.index_columns as ic
                  on ic.index_id = i.index_id and ic.object_id = i.object_id
                inner join sys.columns as c2 on ic.column_id = c2.column_id and i.object_id = c2.object_id
              WHERE (i.is_unique_constraint = 1) and ic.column_id = c.column_id and i.object_id=c.object_id)) as is_unique
              from sys.columns as c
              WHERE object_name(c.object_id)  in (select table_name	FROM information_schema.Tables WHERE table_type = 'Base Table')
              order by table_name",
        :primary_keys => "SELECT i.name AS index_name,ic.index_column_id,key_ordinal,c.name AS column_name,TYPE_NAME(c.user_type_id)AS column_type
                    ,is_identity,OBJECT_NAME(i.object_id) as table_name FROM sys.indexes AS i INNER JOIN sys.index_columns AS ic ON
                    i.object_id = ic.object_id AND i.index_id = ic.index_id INNER JOIN sys.columns AS c ON ic.object_id = c.object_id
                    AND c.column_id = ic.column_id WHERE i.is_primary_key = 1 order by table_name",
        :foreign_keys => "SELECT f.name AS foreign_key_name, object_name(f.parent_object_id) AS table_name , col_name(fc.parent_object_id, fc.parent_column_id) AS child_id
                    ,object_name (f.referenced_object_id) AS parent_table ,col_name(fc.referenced_object_id, fc.referenced_column_id) AS parent_id FROM sys.foreign_keys AS f
                    INNER JOIN sys.foreign_key_columns AS fc ON f.object_id = fc.constraint_object_id where OBJECT_NAME(f.parent_object_id) not in ('sysdiagrams')  order by table_name"
       }
     end

     sql_statements.each_key do |key|
       define_method("#{key}_for") do |table|
         send(key, table).select { |item| item[:table_name] == table_name(table) }
       end unless key == :tables
     end

  end

end

04FebUsing Ruby to Generate LightSpeed Models – Part 1

This is the first in a multi-part post on a little ruby application I wrote to generate models for LightSpeed.

The ultimate goal is to consume the entities we generate in this series with IronRuby and perform some data access.

Today I’ll post the code I wrote for creating the database connection. At this moment there is only code there to connect tho sql server. But I may want to add providers later if I decide to keep using this code. That’s why some bits are in a separate module.

This are the specs I wrote for the connection manager. The connection manager is the class that reads the database config, gets a connection and executes sql statements. I think this code is pretty simple so I won’t put a line-by-line explanation.

It uses DBI to connect to the database and reads out the results of the executed sql statement. In the next post I’ll talk about getting the metadata that is required from sql server.

DB::DbiSqlServer
- should return a connection
- should say it’s an ODBC connection when a dsn is provided
- should return the correct connection string for an ODBC connection


module DB

	module SqlConnectionManager

		DEFAULT_CONFIG_PATH = File.dirname(__FILE__) + '/../config/database.yml'

		attr_reader :connection_string, :connection

		def initialize(config=DEFAULT_CONFIG_PATH)
		  if config.is_a? Hash
		    initialize_config config
		  else
		    read_config config
	    end
		end

		def read_config(config_path, config_name = 'sqlserver')
			initialize_config(YAML::load(File.open(config_path || DEFAULT_CONFIG_PATH))[config_name])
		end

		def initialize_config(config)
		  @config = config
			@connection=nil
	  end

		def odbc?
		  return true unless @config.nil? || @config['dsn'].nil?
		  false
		end

	end

	class DbiSqlServer
		include SqlConnectionManager

		def connection
			if @connection.nil?
			  @connection = DBI.connect(connection_string, @config['username'], @config['password'])
			end
			@connection
		end

		def connection_string
		  if odbc?
		    "DBI:ODBC:#{@config['dsn']}"
		  else
		    "DBI:ADO:Provider=SQLOLEDB;Data Source=#{@config['host']};Initial Catalog=#{@config['database']};User ID=#{@config['username']};Password=#{@config['password']};"
	    end
	  end

		def fetch_all(sql_statement)
			result = []
			connection.execute sql_statement do |statement|
				while row = statement.fetch do
					r = {}
					row.each_with_name do |val, name|
						r[name.to_sym] = val
					end
					result << r
				end
			end
			result
		end

		def execute_non_query(sql_statement)
		  connection.do sql_statement
		end

	end

end

27NovRe: The difference between meta programming and IL weaving

Ayende replied to my post from this morning. His point is that the in order to be able to do meta programming Reflection.Emit isn’t enough because it happens after the compilation has taken place. And in order to do meta programming you need to be able to do that during the compilation step. This is my reply, hence the title :)

Meta-programming can be achieved by having the language implementation change classes or generate classes at some point. In dynamic languages that is generally at run time, it’s most common use is where the data format drives the code ie. a database, csv files etc. For the sake of this discussion i’m going to keep it at runtime, if meta programming occurs at compilation time it loses a lot of its power, how is it going to respond to changes at runtime like changes in the data schema.

You could do this by having an interface of your implementation, If you’re going to use an interface implementation you can just as well generate the class or implement the class. Another thing you need for meta programming is duck typing. So for meta programming to happen you would have to forgo things like type checking, looking for existing methods on classes etc. You would lose the biggest advantage of a statically typed language and one of the biggest reasons for having a compiler at all. So, with all due respect, I wonder at that point why use a static typed language implemented on a compiler, that will make things really hard for you, at all when you can achieve the same things in other dynamically typed languages with hardly any effort.

If all you want is ruby with c# syntax, then you will lose exactly what makes ruby so attractive its more natural syntax. At this moment the IronRuby implementation still needs a lot of work but you could use Ruby.NET and get a good working version of Ruby that runs and compiles on the CLR. Or use ironpython that implementation is a lot more usable at this moment and you can do interop with .NET assemblies.

With Reflection.Emit you can get similar things. You can’t modify existing classes but when you would be using something like an IoC container that keeps track of dynamic proxy wrappers that are being generated so that it can always use the latest proxy wrapper, that way you could achieve almost the same thing. This won’t be the fastest method around but it would give you most the needed abilities. You would still need at least some interfaces and know about those interfaces upfront. After all MSIL is much like a dynamic language.

I still wouldn’t exactly call it meta programming but it can come close, you wouldn’t be able to modify existing classes but you would be able to add functionality to classes. It also won’t be the most easy thing to implement correctly but in theory it can be done.

Method missing in ruby works because the ruby interpreter walks up its tree of objects looking for an implementation of method_missing but that’s also what makes method missing not the fastest mechanism around.

This whole discussion made me think of a generalization Greenspun’s 10th law: “any sufficiently complicated program in a statically-typechecked language contains an ad-hoc, informally-specified bug-ridden slow implementation of a dynamically-checked language.” ;)

What would the implementation of IDynamicObject be ? Would it suddenly drop the type checking for implementing classes and defer that to runtime? How would you like to see IDynamicObject happening without losing static typing along the way ? I would like to find out these things interest me tremendously, I’m always looking for ways to make C# more dynamic but I don’t want to lose static typing along the way.  I would like to use C# instead of C++ for speed and use IronRuby for the rest for example, shifting those languages one era along.

19NovRuby-In-Steel is giving intellisense for ironruby in VS

The guys over at Sapphire Steel have been doing great work with the current implementation of IronRuby

Today they put a blog post online showing you how far they got for implementing intellisense.

 

I’m pretty happy with the progress ironruby is making there are a whole bunch of people contributing. The guys from the Mono team have been following the development as well to make sure you can run ironruby on MS .NET or on Mono which makes it a really good alternative to the C-ruby implementation as soon as Ironruby has matured enough.

If you have some free time and are interested in helping some really smart people implementing a programming language I suggest you check out the ironruby.net website and join the mailinglist on rubyforge.

29OctA little browser with ironruby and wpf

Whilst preparing for my talk on saturday I got to play a little with Iron ruby and wpf.

One of my experiments was to create a little browser which i dubbed biffy :)

You can download it here: biffy.zip

 

del.icio.us tags: , ,

Recent Flickrs

    Blogroll

    Recent Listening

    Scrobbler