modelling 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2007-2012 Ryan Allen, Ian Leitch, John Barton, Mark Turnley, Steve Hodgkiss, FlashDen Pty Ltd
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,64 @@
1
+ This module, when included, enforces the typical instantiation pattern
2
+ that accepts a hash of attributes, like so:
3
+
4
+ class Car
5
+ include Modelling
6
+ attr_accessor :make
7
+ attr_accessor :model
8
+ end
9
+
10
+ car = Car.new(:make => 'Lotus', :model => 'Elise')
11
+ car.make # => 'Lotus'
12
+ car.model # => 'Elise'
13
+
14
+ Additionally you get three meta methods for making your so called domain
15
+ modelling a little more concise, these three methods are:
16
+
17
+ * attributes
18
+ * collections
19
+ * maps
20
+ * structs
21
+
22
+ Attributes simply is an alias for attr_accessor, collections defines accessors
23
+ that are arrays, and maps defines hashes. The constructor ensures that each
24
+ map and collection are initalized as [] and {} respectively by default:
25
+
26
+ class Car
27
+ include Modelling
28
+ attributes :make, :model
29
+ collections :tyres, :accessories
30
+ maps :dealer_locations, :telephone_services
31
+ end
32
+
33
+ car = Car.new
34
+ car.make # => nil
35
+ car.model # => nil
36
+ car.tyres # => []
37
+ car.accessories # => []
38
+ car.dealer_locations # => {}
39
+ car.telephone_services # => {}
40
+
41
+ Structs are as the name suggests, structs. Or more specifically OpenStructs:
42
+
43
+ class Car
44
+ include Modelling
45
+ structs :features
46
+ end
47
+
48
+ car.features.abs true
49
+ car.features.air_con true
50
+ car.features.valves 8
51
+
52
+ TODO: WRITE DOCS FOR NEW CUSTOM INITIALIZERS!!!1 (AND UPDATE DOCS ABOVE,
53
+ THEY ARE LIKE OUT OF DATE OR SOMETHING).
54
+ i.e. collections :categories => CategoryCollection
55
+ and
56
+ attributes :total => Proc.new { Money.new(0) }
57
+ and
58
+ maps :domain => CustomDNSWithHashLookupAwesome
59
+
60
+ This makes modelling with PORO's [1] more eloquent, and stops us from
61
+ having to write and re-write constructors that accept hashes, as
62
+ is typically done.
63
+
64
+ [1] http://en.wikipedia.org/wiki/POJO
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,78 @@
1
+ require 'modelling/version'
2
+ require 'ostruct'
3
+
4
+ module Modelling
5
+
6
+ def self.included(receiver)
7
+ receiver.extend ClassMethods
8
+ end
9
+
10
+ module ClassMethods
11
+ def inherited(descendant)
12
+ descendant.instance_variable_set(:@members, members.dup)
13
+ super
14
+ end
15
+
16
+ def attributes(*args)
17
+ generate_accessors_from_args(args, Proc.new { nil })
18
+ end
19
+
20
+ def collections(*args)
21
+ generate_accessors_from_args(args, Proc.new { Array.new })
22
+ end
23
+
24
+ def maps(*args)
25
+ generate_accessors_from_args(args, Proc.new { Hash.new })
26
+ end
27
+
28
+ def structs(*args)
29
+ generate_accessors_from_args(args, Proc.new { OpenStruct.new })
30
+ end
31
+
32
+ def members
33
+ @members ||= {}
34
+ end
35
+
36
+ private
37
+
38
+ def generate_accessors_from_args(args, default_initializer)
39
+ names_to_initializer = args.last.is_a?(Hash) ? args.pop : {}
40
+ args.each do |name|
41
+ names_to_initializer[name] = default_initializer
42
+ end
43
+ generate_accessors(names_to_initializer)
44
+ end
45
+
46
+ def generate_accessors(names_to_initializer)
47
+ names_to_initializer.each do |name, initializer|
48
+ create_accessor(name)
49
+ if initializer.is_a?(Proc)
50
+ members[name] = initializer
51
+ else
52
+ members[name] = Proc.new { initializer.new }
53
+ end
54
+ end
55
+ end
56
+
57
+ def create_accessor(name)
58
+ instance_eval { attr_accessor name }
59
+ end
60
+
61
+ end
62
+
63
+ def members
64
+ self.class.members
65
+ end
66
+
67
+ def initialize(args = {})
68
+ members.each do |accessor, initializer|
69
+ if initializer.arity > 0
70
+ send "#{accessor}=", initializer.call(self)
71
+ else
72
+ send "#{accessor}=", initializer.call
73
+ end
74
+ end
75
+ args.each { |name, value| send "#{name}=", value }
76
+ end
77
+
78
+ end
@@ -0,0 +1,3 @@
1
+ module Modelling
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'modelling/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'modelling'
7
+ s.version = Modelling::VERSION
8
+ s.authors = ['Ryan Allen', 'Steve Hodgkiss', 'Mark Turnley', 'John Barton']
9
+ s.email = ['ryan@eden.cc', 'steve@hodgkiss.me', 'ravagedcarrot@gmail.com', 'jrbarton@gmail.com']
10
+ s.homepage = 'http://github.com/ryan-allen/modelling'
11
+ s.summary = %q{Wraps some common-ish plain-ruby object modelling junk.}
12
+ s.description = %q{We were doing PORO dev on Rails before it was hip.}
13
+
14
+ s.rubyforge_project = 'modelling'
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ['lib']
20
+
21
+ # specify any dependencies here; for example:
22
+ # s.add_development_dependency 'rspec'
23
+ s.add_runtime_dependency 'rspec'
24
+ end
@@ -0,0 +1,153 @@
1
+ require 'bundler'
2
+ Bundler.require
3
+ $: << '.'
4
+ require 'modelling'
5
+
6
+ class User
7
+ include Modelling
8
+ attributes :name, :age
9
+ collections :fav_colours, :biggest_gripes, :test => lambda { 3 }
10
+ end
11
+
12
+ class NonSpecificUser < User
13
+ end
14
+
15
+ class MyArray < Array; end
16
+ class MyHash < Hash; end
17
+
18
+ class Car
19
+ include Modelling
20
+ attributes :name => Proc.new { |car| String.new(car.class.to_s) }
21
+ collections :doors => MyArray
22
+ end
23
+
24
+ class SuperCar < Car
25
+ attributes :bhp => Proc.new { 400 }
26
+ end
27
+
28
+ class Site
29
+ include Modelling
30
+ maps :users => MyHash
31
+ end
32
+
33
+ class Bike
34
+ include Modelling
35
+ attributes :manufacturer
36
+ maps :stickers
37
+ structs :features
38
+ end
39
+
40
+ class LambdaTest
41
+ include Modelling
42
+ attributes :lambda => lambda { "boo" }
43
+ end
44
+
45
+ describe Modelling do
46
+
47
+ specify 'user has name' do
48
+ user = User.new
49
+ user.name = 'Ryan'
50
+ user.name.should eq 'Ryan'
51
+ end
52
+
53
+ specify 'user has age' do
54
+ user = User.new
55
+ user.age = 24
56
+ user.age.should eq 24
57
+ end
58
+
59
+ specify 'user has fav colours collection' do
60
+ user = User.new
61
+ user.fav_colours = [:green, :yellow]
62
+ user.fav_colours.should eq [:green, :yellow]
63
+ end
64
+
65
+ specify 'user has biggest gripes collection' do
66
+ user = User.new
67
+ user.biggest_gripes = [:mediocrity, :CUB_beer]
68
+ user.biggest_gripes.should eq [:mediocrity, :CUB_beer]
69
+ end
70
+
71
+ specify 'attributes are initialized as nil' do
72
+ user = User.new
73
+ user.name.should be_nil
74
+ user.age.should be_nil
75
+ end
76
+
77
+ specify 'collections are initialized as empty array' do
78
+ user = User.new
79
+ user.fav_colours.should be_empty
80
+ user.biggest_gripes.should be_empty
81
+ end
82
+
83
+ it 'can initialize with attributes' do
84
+ user = User.new(:name => 'Ryan')
85
+ user.name.should eq 'Ryan'
86
+ end
87
+
88
+ it 'can initialize with collections' do
89
+ user = User.new(:biggest_gripes => [:mediocrity, :CUB_beer])
90
+ user.biggest_gripes.should eq [:mediocrity, :CUB_beer]
91
+ end
92
+
93
+ specify 'car has doors and all is good' do
94
+ car = Car.new
95
+ car.doors.should be_empty
96
+ end
97
+
98
+ specify 'bike does not bunk on having no collection' do
99
+ bike = Bike.new(:manufacturer => 'Kawasaki')
100
+ # if nothing is rased, we fixed the bug
101
+ end
102
+
103
+ specify 'bike has map of stickers' do
104
+ Bike.new.stickers.should be_empty
105
+ end
106
+
107
+ specify 'cars doors is a my array' do
108
+ Car.new.doors.should be_instance_of MyArray
109
+ end
110
+
111
+ specify 'sites users is a my hash' do
112
+ Site.new.users.should be_instance_of MyHash
113
+ end
114
+
115
+ it 'can initialize with proc and get reference to new instance' do
116
+ car = Car.new
117
+ car.name.should eq String.new(car.class.to_s)
118
+ end
119
+
120
+ specify 'bike has features' do
121
+ bike = Bike.new
122
+ bike.features.should be_instance_of OpenStruct
123
+ end
124
+
125
+ it 'doesnt fail when lambdas with no args are used' do
126
+ LambdaTest.new.lambda.should eq 'boo'
127
+ end
128
+
129
+ context 'inheritence' do
130
+ let(:car) { Car.new }
131
+ let(:super_car) { SuperCar.new }
132
+
133
+ it 'inherits attributes' do
134
+ super_car.doors.should be_instance_of MyArray
135
+ super_car.name.should eq "SuperCar"
136
+ end
137
+
138
+ it 'allows extra attributes' do
139
+ super_car.bhp.should eq 400
140
+ end
141
+
142
+ it 'doesnt mess up the super classes members' do
143
+ car.should_not respond_to(:bhp)
144
+ car.should respond_to(:doors)
145
+ car.should respond_to(:name)
146
+ end
147
+
148
+ specify 'non specific user inherits attributes' do
149
+ user = NonSpecificUser.new(:name => 'Ryan you cocktard')
150
+ user.name.should eq 'Ryan you cocktard'
151
+ end
152
+ end
153
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: modelling
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Ryan Allen
14
+ - Steve Hodgkiss
15
+ - Mark Turnley
16
+ - John Barton
17
+ autorequire:
18
+ bindir: bin
19
+ cert_chain: []
20
+
21
+ date: 2012-02-03 00:00:00 Z
22
+ dependencies:
23
+ - !ruby/object:Gem::Dependency
24
+ name: rspec
25
+ prerelease: false
26
+ requirement: &id001 !ruby/object:Gem::Requirement
27
+ none: false
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ hash: 3
32
+ segments:
33
+ - 0
34
+ version: "0"
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ description: We were doing PORO dev on Rails before it was hip.
38
+ email:
39
+ - ryan@eden.cc
40
+ - steve@hodgkiss.me
41
+ - ravagedcarrot@gmail.com
42
+ - jrbarton@gmail.com
43
+ executables: []
44
+
45
+ extensions: []
46
+
47
+ extra_rdoc_files: []
48
+
49
+ files:
50
+ - .gitignore
51
+ - .rspec
52
+ - Gemfile
53
+ - MIT-LICENSE
54
+ - README
55
+ - Rakefile
56
+ - lib/modelling.rb
57
+ - lib/modelling/version.rb
58
+ - modelling.gemspec
59
+ - spec/modelling_spec.rb
60
+ homepage: http://github.com/ryan-allen/modelling
61
+ licenses: []
62
+
63
+ post_install_message:
64
+ rdoc_options: []
65
+
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ hash: 3
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ hash: 3
83
+ segments:
84
+ - 0
85
+ version: "0"
86
+ requirements: []
87
+
88
+ rubyforge_project: modelling
89
+ rubygems_version: 1.8.10
90
+ signing_key:
91
+ specification_version: 3
92
+ summary: Wraps some common-ish plain-ruby object modelling junk.
93
+ test_files:
94
+ - spec/modelling_spec.rb