Archive for February, 2008

27FebVisual studio gallery

This morning I found an announcement for the visual studio tools gallery. I went and had a look they have collected heaps of tools, some free most of them not into a website.

I promptly downloaded a couple of tools. One of them is something I recently discovered I need, local history. That is in between check-ins a file can also change but that isn’t recorded in source control so i can’t revert or view differences. Turns out that there is a project on codeplex that allows you to do just that. It’s called local history :)

 

Technorati Tags:

27FebConsuming YouTube using XLinq

I had to implement an integration with youtube for a client yesterday. Google provides API’s but they are for Java and PHP. I’m using C# for this project. So I decided to use XLinq to fetch the feeds and parse them into classes for what I needed.

I only need titles, movies and a thumbnail for each item. So I haven’t implemented all of the properties. And I am impressed. From having no exposure to XLinq whatsoever to having it parse feeds and being able to use those feeds in my monorail application took me about an hour. Since this is the very first time I use XLinq I imagine there is room for improvement, please tell me so when I’m wrong.

The classes I show here can be used as follows:

YouTubePlayList.LoadForUser("<>").ForEach(pl => Response.Write("" + pl.Id + ""));

var url = http://gdata.youtube.com/feeds/api/playlists/<
;
YouTubeCollection.LoadFrom(url).ForEach(yt => Response.Write(yt.Title + ", " + yt.MovieUrl + ""));

public class YouTubeCollection : List
    {
        public YouTubeCollection()
        {
        }

        public YouTubeCollection(IEnumerable collection)
            : base(collection)
        {
        }

        public static YouTubeCollection LoadFrom(string uri)
        {
            var feed = XElement.Load(uri);

            XNamespace ns = "http://www.w3.org/2005/Atom";
            XNamespace media = "http://search.yahoo.com/mrss/";

            var list = new YouTubeCollection(from item in feed.Elements(ns + "entry").Elements(media + "group")
                        select new YouTubeItem
                        {
                            Title = item.Element(media + "title").Value,
                            MovieUrl = (from el in item.Elements(media + "content")
                                     where el.Attribute("type").Value == "application/x-shockwave-flash"
                                     select el.Attribute("url").Value).First(),
                             ThumbnailUrl = (from el in item.Elements(media + "thumbnail")
                                             select el.Attribute("url").Value).First()
                        });

            return list;
        }

    }

    public class YouTubePlayList : List
    {
        public YouTubePlayList()
        {
        }

        public YouTubePlayList(IEnumerable collection) : base(collection)
        {
        }

        public static YouTubePlayList LoadForUser(string user)
        {
            var url = string.Format("http://gdata.youtube.com/feeds/api/users/{0}/playlists", user);

            var feed = XElement.Load(url);

            XNamespace ns = "http://www.w3.org/2005/Atom";
            XNamespace gd = "http://schemas.google.com/g/2005";

            var list = new YouTubePlayList(from item in feed.Elements(ns + "entry")
                                           select new YouTubePlayListItem
                                             {
                                                 Name = item.Element(ns + "title").Value,
                                                 Id = item.Element(gd + "feedLink").Attribute("href").Value
                                             });

            return list;
        }
    }

    [DataContract]
    public class YouTubePlayListItem
    {
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public string Id { get; set; }
    }

    [DataContract]
    public class YouTubeItem
    {
        private string _id;
        [DataMember]
        public string Id
        {
            get
            {
                return MovieUrl.Split('/').Last();
            }
            set
            {
                _id = value;
            }
        }

        [DataMember]
        public string Title { get; set; }

        [DataMember]
        public string MovieUrl { get; set; }

        [DataMember]
        public string ThumbnailUrl { get; set; }
    }

 

Technorati Tags: ,

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

07FebMore on Mac KeyBindings

The biggest problem so far I’ve had when switching from windows to a mac were the shortcut keys, and mostly the inconsistency thereof. It turns out there is a way to manipulate the keybindings for all cocoa apps, which should make them consistent across all good cocoa citizens. Firefox isn’t one of those citizens neither is firefox 3.0.

I uninstalled quicksilver because I couldn’t work out what it would do for me and didn’t want to spend time figuring it out either. This liberated my ctrl-space for visual studio.  I remapped alt-insert to alt-i and that works for me. Then I brought some consistency in the way my keys behave across all cocoa apps.

I solved my problem with the shortcut keys by following the instructions that can be found in the following posts.
They talk about editing a file by hand and saving it, but for those that like a GUI there is one for it.

The GUI application: KeyBindingsEditor

The links with some instructions and background information.

http://blog.macromates.com/2005/key-bindings-for-switchers/

http://www.hcs.harvard.edu/~jrus/site/cocoa-text.html

The last post lists a couple of predefined keybinding files like one for emacs

http://www.hcs.harvard.edu/~jrus/site/KeyBindings/Emacs%20Esc%20Bindings.dict

or windows key bindings

http://www.hcs.harvard.edu/~jrus/site/KeyBindings/Emacs%20Esc%20Bindings.dict

 

Guess which ones I took and it’s not emacs ;) I actually just took a couple of keybindings. The ones that I use the most

/***** ARROWS *****/

    “^\UF700″   = “moveToBeginningOfParagraph:”;    /* C-up         Move to beginning of paragraph */
    “^\UF701″   = “moveToEndOfParagraph:”;          /* C-down       Move to end of paragraph */

    “^$\UF700″  = “moveToBeginningOfParagraphAndModifySelection:”;
                                                    /* C-Shft-up    Select to beginning of paragraph */
    “^$\UF701″  = “moveToEndOfParagraphAndModifySelection:”;
                                                    /* C-Shft-down  Select to end of paragraph */

    “^\UF702″   = “moveWordLeft:”;                  /* C-left       Move word left */
    “^\UF703″   = “moveWordRight:”;                 /* C-right      Move word right */

    “$^\UF702″  = “moveWordLeftAndModifySelection:”;
                                                    /* C-Shft-left  Select word left */
    “$^\UF703″  = “moveWordRightAndModifySelection:”;
                                                    /* C-Shft-right Select word right */

/***** CTRL + LETTERS *****/

    “^a”        = “selectAll:”;                     /* C-a          Select all */

    “^x”        = “cut:”;                           /* C-x          Cut */
    “^c”        = “copy:”;                          /* C-c          Copy */
    “^v”        = “paste:”;                         /* C-v          Paste */

    “^z”        = “undo:”;                          /* C-z          Undo */
    “^y”        = “redo:”;                          /* C-y          Redo */

    “^s”        = “save:”;                          /* C-s          Save */
    “^S”        = “saveAs:”;                        /* C-Shft-s     Save as */
 

del.icio.us Tags: ,,

06FebOn software development: the myth of no maintenance etc.

Jeremy Miller put a very intersting post up about the First causes in software development 
While I don’t always like the how of delivering his messages, I think Jeremy is generally spot on. In fact he seems to voice my thoughts much more eloquently than I ever could. Anyway his post or series of posts is dealing with some of the choices he made concerning tools and development philosophy and it also tries to explain that while these tools seem to work today, there won’t be anything stopping him if something better comes along.

Now in that article he links to an article by the pragmatic programmers on the principle of DRY and orthogonality. For me the biggest problem of software development is not the techniques or the patterns but it’s the actual language people use. Till this day I still don’t know what orthogonality means although I understand what that word means in a development context. There are countless examples where people overcomplicate things by using difficult words, this is just one more. Anyway I digress :)

The article series he’s referring to is pretty interesting. If you have some time to kill I suggest you read them. It are 10 articles:
Part I – Don’t live with broken windows

Part II – Orthogonality and the DRY Principle

Part III – Good enough software

Part IV – Abstraction and Detail

Part V – Building adaptable systems

Part VI – Programming close to the domain

Part VII – Programming is gardening, not engineering

Part VIII – Tracer Bullets and Prototypes

Part IX – Programming defensively

Part X – Plain text and xml

 

The reason that I put these links up is not only because they are a great read but also because one of the things they say in one of the articles is that after you wrote 10 lines of code or so you’re effectively in maintenance mode the green field is gone. And that couldn’t be more true after I had some internal discussion about it I definitely agree with that statement and as such one of the primary goals of your development should not be on getting it out the door as quickly as possible but building it in such a way that you or somebody else can get in there and make changes without throwing away half the code base.

I hope you enjoy them as much as I did

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

05FebCompiling Mono and IronRuby on OSX Leopard

I tried to compile IronRuby on OS X (leopard) with the dmg I downloaded from the mono website, and that didn’t work.

I then uninstalled that mono version by running monoUninstall.sh and proceeded to get mono from subversion. I’m putting these steps on my blog more for future reference when I decide to reinstall my box for some reason.

Download gettext, pkgconfig and glib2.0

extract the archives and build them in the following order gettext, pkgconfig, glib2.0

./configure –prefix=/opt/local
make
sudo make install

At this point it would be wise to set the PKG_CONFIG_PATH environment variable. I added the following line to ~/.bash_profile

export PKG_CONFIG_PATH=”/usr/local/lib/pkgconfig:/opt/local/lib/pkgconfig”

next it’s time to check out the mono sources from their repositories

cd ~/
mkdir tools
mkdir mono
svn co svn://anonsvn.mono-project.com/source/trunk/mono
svn co svn://anonsvn.mono-project.com/source/trunk/mcs
svn co svn://anonsvn.mono-project.com/source/trunk/libgdiplus
svn co svn://anonsvn.mono-project.com/source/trunk/moon
svn co svn://anonsvn.mono-project.com/source/trunk/olive
svn co svn://anonsvn.mono-project.com/source/trunk/gtk-sharp

checking those out will take a while

now go into the mono directory and build mono

cd mono
./autogen.sh –prefix=/opt/local/mono –with-preview=yes –with-moonlight=yes

–with-preview enables the .NET 3.5 features that have been implemented so far
–with-moonlight enables support for moonlight

make
sudo make install

This will also take some time and when it completes you can check if mono is installed by typing mono -V

That’s it for mono, now onto IronRuby

cd ~/tools

svn co http://ironruby.rubyforge.org/svn/trunk ironruby

sudo gem install pathname2

rake compile mono=1

And that should be all :)

UPDATE: I’ve got new instructions for building IronRuby

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

04FebOSX and Resharper get in eachothers way

And today I discovered that using unity severly interferes with my flow in visual studio.

I have ctrl-space mapped to quicksilver on mac osx which would mean I have to rebind either autocompletion or quicksilver, and it sure as hell won’t be my autocompletion. I think it will be too hard to unset that binding in my brain I’ve been using ctrl-space for about 10 years now, without even thinking about it. I even try to use it in Word but of course that doesn’t work ;)
The typing speed is also a little bit too sluggish for me to actually enjoy working in visual studio in unity mode. I decided to get back to a ruby project in textmate :)
I’ll try later on if it’s doable through full screen mode in fusion; and if that doesn’t work, I’ll have no other option than to boot into vista if I have to do .NET work.

There is another key missing from the mac keyboard, the insert key (and I have to admit about this one I’m definitely not that happy – what were they thinking??). So far the keyboard is the hardest to get used to. I mean those would probably be my most used shortcuts : ctrl – arrow, home, end, alt-insert and i now have to learn how to use different combinations and different ones in every program.

In other news, today i found myself using alt-C and alt-V on my windows keyboard when I wanted to copy paste. I think all the shortcuts have no right or wrong combination but it won’t be long before I master the ones on the mac that’s for sure.

I feel a lot better having that off my chest.


Recent Flickrs

    Blogroll

    Recent Listening

    Scrobbler