Permalink
Browse files

Rewrite. Package as a gem.

  • Loading branch information...
1 parent fcd628e commit e9ba8140b7677cace0110272e81d518ac808f3bb @stevehodgkiss stevehodgkiss committed Feb 3, 2012
Showing with 274 additions and 216 deletions.
  1. +4 −0 .gitignore
  2. +1 −0 .rspec
  3. +3 −0 Gemfile
  4. +6 −0 Rakefile
  5. +80 −0 lib/modelling.rb
  6. +3 −0 lib/modelling/version.rb
  7. +24 −0 modelling.gemspec
  8. +0 −87 modelling.rb
  9. +0 −122 modelling_test.rb
  10. +0 −7 rakefile.rb
  11. +153 −0 spec/modelling_spec.rb
View
@@ -0,0 +1,4 @@
+*.gem
+.bundle
+Gemfile.lock
+pkg/*
View
1 .rspec
@@ -0,0 +1 @@
+--color
View
@@ -0,0 +1,3 @@
+source "http://rubygems.org"
+
+gemspec
View
@@ -0,0 +1,6 @@
+require 'bundler/gem_tasks'
+
+require 'rspec/core/rake_task'
+RSpec::Core::RakeTask.new(:spec)
+
+task :default => :spec
View
@@ -0,0 +1,80 @@
+require 'modelling/version'
+require 'ostruct'
+
+module Modelling
+
+ def self.included(receiver)
+ receiver.extend ClassMethods
+ end
+
+ module ClassMethods
+ # A descendent gets a copy of the super classes
+ # attributes when inheritence is used
+ def inherited(descendant)
+ descendant.instance_variable_set(:@members, members.dup)
+ super
+ end
+
+ def attributes(*args)
+ generate_accessors_from_args(args, Proc.new { nil })
+ end
+
+ def collections(*args)
+ generate_accessors_from_args(args, Proc.new { Array.new })
+ end
+
+ def maps(*args)
+ generate_accessors_from_args(args, Proc.new { Hash.new })
+ end
+
+ def structs(*args)
+ generate_accessors_from_args(args, Proc.new { OpenStruct.new })
+ end
+
+ def members
+ @members ||= {}
+ end
+
+ private
+
+ def generate_accessors_from_args(args, default_initializer)
+ names_to_initializer = args.last.is_a?(Hash) ? args.pop : {}
+ args.each do |name|
+ names_to_initializer[name] = default_initializer
+ end
+ generate_accessors(names_to_initializer)
+ end
+
+ def generate_accessors(names_to_initializer)
+ names_to_initializer.each do |name, initializer|
+ create_accessor(name)
+ if initializer.is_a?(Proc)
+ members[name] = initializer
+ else
+ members[name] = Proc.new { initializer.new }
+ end
+ end
+ end
+
+ def create_accessor(name)
+ instance_eval { attr_accessor name }
+ end
+
+ end
+
+ def members
+ self.class.members
+ end
+
+ def initialize(args = {})
+ members.each do |accessor, initializer|
+ if initializer.arity > 0
+ send "#{accessor}=", initializer.call(self)
+ else
+ send "#{accessor}=", initializer.call
+ end
+ end
+ args.each { |name, value| send "#{name}=", value }
+ end
+
+end
View
@@ -0,0 +1,3 @@
+module Modelling
+ VERSION = "0.0.1"
+end
View
@@ -0,0 +1,24 @@
+# -*- encoding: utf-8 -*-
+$:.push File.expand_path('../lib', __FILE__)
+require 'modelling/version'
+
+Gem::Specification.new do |s|
+ s.name = 'modelling'
+ s.version = Modelling::VERSION
+ s.authors = ['Ryan Allen', 'Steve Hodgkiss', 'Mark Turnley', 'John Barton']
+ s.email = ['ryan@eden.cc', 'steve@hodgkiss.me', 'ravagedcarrot@gmail.com', 'jrbarton@gmail.com']
+ s.homepage = ''
+ s.summary = %q{TODO: Write a gem summary}
+ s.description = %q{TODO: Write a gem description}
+
+ s.rubyforge_project = 'modelling'
+
+ s.files = `git ls-files`.split('\n')
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split('\n')
+ s.executables = `git ls-files -- bin/*`.split('\n').map{ |f| File.basename(f) }
+ s.require_paths = ['lib']
+
+ # specify any dependencies here; for example:
+ # s.add_development_dependency 'rspec'
+ s.add_runtime_dependency 'rspec'
+end
View
@@ -1,87 +0,0 @@
-require 'ostruct'
-
-module Modelling
-
- class << self
-
- def append_features(receiver)
- initialize_members_classvar(receiver)
- bind_attributes_meta_method(receiver)
- bind_maps_meta_method(receiver)
- bind_collection_meta_method(receiver)
- build_structs_meta_method(receiver)
- bind_default_constructor(receiver)
- end
-
- def generate_accessors(receiver, names, initializer)
- receiver.instance_eval do
- names.each do |name|
- attr_accessor name
- @@members[self][name] = initializer
- end
- end
- end
-
- def generate_adhoc_accessors(receiver, names_to_class_or_proc)
- receiver.instance_eval do
- names_to_class_or_proc.each do |name, class_or_proc|
- attr_accessor name
- if class_or_proc.is_a?(Proc)
- @@members[self][name] = class_or_proc
- else
- @@members[self][name] = Proc.new { class_or_proc.new }
- end
-
- end
- end
- end
-
- private
-
- def initialize_members_classvar(receiver)
- receiver.instance_eval do
- @@members ||= {}; @@members[self] ||= {}
- end
- end
-
- def bind_meta_method(receiver, name, initializer)
- receiver.instance_eval { class << self; self; end }.instance_eval do
- define_method name do |*args|
- if args.last.is_a?(Hash)
- Modelling.generate_adhoc_accessors(self, args.pop)
- end
- Modelling.generate_accessors(self, args, initializer)
- end
- end
- end
-
- def bind_attributes_meta_method(receiver)
- bind_meta_method(receiver, :attributes, Proc.new { nil })
- end
-
- def bind_collection_meta_method(receiver)
- bind_meta_method(receiver, :collections, Proc.new { Array.new })
- end
-
- def bind_maps_meta_method(receiver)
- bind_meta_method(receiver, :maps, Proc.new { Hash.new })
- end
-
- def build_structs_meta_method(receiver)
- bind_meta_method(receiver, :structs, Proc.new { OpenStruct.new })
- end
-
- def bind_default_constructor(receiver)
- receiver.class_eval do
- def initialize(args = {})
- @@members[self.class].each do |accessor, initializer|
- send "#{accessor}=", initializer.call(self)
- end
- args.each { |name, value| send "#{name}=", value }
- end
- end
- end
-
- end
-
-end
View
@@ -1,122 +0,0 @@
-require 'test/unit'
-require 'modelling'
-
-# this raises an error if the class vars are not initialized by
-# default, we do this here before the unit tests below so we can
-# test for this case before other classes start using their class
-# level macros :) complete hack, but it fulfils the test criteria
-class BlankSlate; include Modelling; end
-BlankSlate.new
-
-class User
- include Modelling
- attributes :name, :age
- collections :fav_colours, :biggest_gripes
-end
-
-class MyArray < Array; end
-class MyHash < Hash; end
-
-class Car
- include Modelling
- attributes :name => Proc.new { |car| String.new(car.class.to_s) }
- collections :doors => MyArray
-end
-
-class Site
- include Modelling
- maps :users => MyHash
-end
-
-class Bike
- include Modelling
- attributes :manufacturer
- maps :stickers
- structs :features
-end
-
-class ModellingTest < Test::Unit::TestCase
-
- def test_can_has_domain_builder
- assert Modelling
- end
-
- def test_user_has_name
- user = User.new
- user.name = 'Ryan'
- assert_equal 'Ryan', user.name
- end
-
- def test_user_has_age
- user = User.new
- user.age = 24
- assert_equal 24, user.age
- end
-
- def test_user_has_fav_colours_collection
- user = User.new
- user.fav_colours = [:green, :yellow]
- assert_equal [:green, :yellow], user.fav_colours
- end
-
- def test_user_has_biggest_gripes_collection
- user = User.new
- user.biggest_gripes = [:mediocrity, :CUB_beer]
- assert_equal [:mediocrity, :CUB_beer], user.biggest_gripes
- end
-
- def test_attributes_are_initialized_as_nil
- user = User.new
- assert_nil user.name
- assert_nil user.age
- end
-
- def test_collections_are_initialized_as_empty_array
- user = User.new
- assert_equal [], user.fav_colours
- assert_equal [], user.biggest_gripes
- end
-
- def test_can_initialize_with_attributes
- user = User.new(:name => 'Ryan')
- assert_equal 'Ryan', user.name
- end
-
- def test_can_initialize_with_collections
- user = User.new(:biggest_gripes => [:mediocrity, :CUB_beer])
- assert_equal [:mediocrity, :CUB_beer], user.biggest_gripes
- end
-
- def test_car_has_doors_and_all_is_good
- car = Car.new
- assert_equal [], car.doors
- end
-
- def test_bike_does_not_bunk_on_having_no_collection
- bike = Bike.new(:manufacturer => 'Kawasaki')
- # if nothing is rased, we fixed the bug
- end
-
- def test_bike_has_map_of_stickers
- assert_equal({}, Bike.new.stickers)
- end
-
- def test_cars_doors_is_a_my_array
- assert_kind_of MyArray, Car.new.doors
- end
-
- def test_sites_users_is_a_my_hash
- assert_kind_of MyHash, Site.new.users
- end
-
- def test_can_initialize_with_proc_and_get_reference_to_new_instance
- car = Car.new
- assert_equal String.new(car.class.to_s), car.name
- end
-
- def test_bike_has_features
- bike = Bike.new
- assert_kind_of OpenStruct, bike.features
- end
-
-end
View
@@ -1,7 +0,0 @@
-task :default do
- Rake::Task['run_tests'].invoke
-end
-
-task :run_tests do
- require 'modelling_test'
-end
Oops, something went wrong.

0 comments on commit e9ba814

Please sign in to comment.