modelling 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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