yaml-model 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ Gemfile.lock
2
+ pkg/*
3
+ *.gem
4
+ .bundle
5
+ vendor/*
6
+ *.swp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in yaml-model.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ task :default => :test
5
+
6
+ desc "unit tests"
7
+ task :test do
8
+ exec 'bundle exec rspec test/*.rb'
9
+ end
data/lib/yaml-model.rb ADDED
@@ -0,0 +1,173 @@
1
+ require 'yaml'
2
+ require 'yaml-model/version'
3
+
4
+ class YAML_Model
5
+
6
+ class Error < Exception
7
+ end
8
+
9
+ def self.reset!
10
+ @@database_filename = nil
11
+
12
+ @@database = {
13
+ :next_oid => 1,
14
+ :data => {}
15
+ }
16
+ end
17
+
18
+ reset!
19
+
20
+ attr_reader :id
21
+
22
+ @@volatile = [ :@volatile ]
23
+
24
+ def self.all
25
+ @@database[ :data ][ self.name ] ||= []
26
+ end
27
+
28
+ def assert( assertion, info )
29
+ raise Error.new( info.inspect ) unless assertion
30
+ end
31
+
32
+ def assert_type( variable, types )
33
+ assert( [types].flatten.inject(false){|result,type|result||=(type===variable)}, "Invalid type: `#{variable.class.name}`" )
34
+ end
35
+
36
+ def self.type attribute, types, &block
37
+ define_method attribute do
38
+ instance_eval "@#{attribute}"
39
+ end
40
+ define_method "#{attribute}=".to_sym do |value|
41
+ assert_type value, types
42
+ instance_exec( value, &block ) if block_given?
43
+ instance_eval "@#{attribute} = value"
44
+ end
45
+ end
46
+
47
+ def self.init *attributes, &block
48
+ define_method :initialize do |*args|
49
+ attributes.each do |attribute|
50
+ self.send( "#{attribute}=".to_sym, args.shift )
51
+ end
52
+ self.instance_eval( &block ) if block_given?
53
+ end
54
+ end
55
+
56
+ def self.[]( id )
57
+ all.select{|n|n.id==id}.first
58
+ end
59
+
60
+ def self.load!
61
+ @@database = YAML.load( File.read( @@database_filename.to_s ) ) if File.exists?( @@database_filename.to_s )
62
+ end
63
+
64
+ def self.filename=( filename )
65
+ @@database_filename = filename
66
+ self.load!
67
+ end
68
+
69
+ def self.to_yaml
70
+ @@database.to_yaml
71
+ end
72
+
73
+ def self.save!
74
+ if @@database_filename
75
+ File.open( @@database_filename, 'w' ) do |file|
76
+ file.write( self.to_yaml )
77
+ end
78
+ end
79
+ end
80
+
81
+ def self.each &block
82
+ all.each &block
83
+ end
84
+
85
+ def self.select &block
86
+ all.select &block
87
+ end
88
+
89
+ def self.filter hash
90
+ select do |this|
91
+ hash.keys.inject( true ) do |result,variable|
92
+ this.instance_eval( "@#{variable}" ) == hash[ variable ]
93
+ end
94
+ end
95
+ end
96
+
97
+ def self.volatile variable
98
+ @@volatile << "@#{variable}".to_sym
99
+ end
100
+
101
+ def to_yaml_properties
102
+ instance_variables - @@volatile
103
+ end
104
+
105
+ def self.create( *args )
106
+ this = self.new( *args )
107
+ this.instance_eval do
108
+ @id = @@database[ :next_oid ]
109
+ @id.freeze
110
+ end
111
+ @@database[ :next_oid ] += 1
112
+ @@database[ :data ][ this.class.name ] ||= []
113
+ @@database[ :data ][ this.class.name ] << this
114
+ this
115
+ end
116
+
117
+ def delete
118
+ @@database[ :data ][ self.class.name ].delete( self )
119
+ end
120
+
121
+ def self.sort_by( *attributes )
122
+ define_method '<=>'.to_sym do |other|
123
+ attributes.map{|a|self.send(a)} <=> attributes.map{|a|other.send(a)}
124
+ end
125
+ end
126
+
127
+ sort_by :id
128
+
129
+ def self.has( that_attribute_plural, that_class, many_to_many = false )
130
+ if many_to_many
131
+ this_class = self
132
+ this_class_name, that_class_name = [this_class,that_class].map{|n|n.name.split(':')[-1]}
133
+ this_attribute_singular = this_class_name.downcase.to_sym
134
+ that_attribute_singular = that_class_name.downcase.to_sym
135
+ via_class_name = [ this_class_name, that_class_name ].sort.map{|n|n.capitalize}.join('')
136
+ via_class = eval( "#{via_class_name}||=Class.new(YAML_Model)" )
137
+ via_attribute_plural = ( via_class_name.downcase + "s" ).to_sym
138
+
139
+ if via_class.instance_variables.empty?
140
+ via_class.type this_attribute_singular, this_class
141
+ via_class.type that_attribute_singular, that_class
142
+ end
143
+
144
+ this_class.has via_attribute_plural, via_class
145
+
146
+ define_method that_attribute_plural do
147
+ send( via_attribute_plural ).map do |via_instance|
148
+ via_instance.send( that_attribute_singular )
149
+ end
150
+ end
151
+
152
+ define_method "add_#{that_attribute_singular}".to_sym do |that_instance|
153
+ via_instance = via_class.create
154
+ via_instance.send( "#{this_attribute_singular}=".to_sym, self )
155
+ via_instance.send( "#{that_attribute_singular}=".to_sym, that_instance )
156
+ end
157
+
158
+ else
159
+
160
+ define_method that_attribute_plural do
161
+ that_class.select do |that_instance|
162
+ that_instance.instance_variables.inject( false ) do |result,variable|
163
+ result ||= that_instance.instance_eval(variable.to_s).class == self.class && that_instance.instance_eval(variable.to_s).id == self.id
164
+ end
165
+ end
166
+ end
167
+
168
+ end
169
+ end
170
+
171
+ at_exit { self.save! }
172
+
173
+ end
@@ -0,0 +1,3 @@
1
+ class YAML_Model
2
+ VERSION = "1.0.1"
3
+ end
data/test/has.rb ADDED
@@ -0,0 +1,77 @@
1
+ require 'yaml-model'
2
+
3
+ describe YAML_Model, "::has" do
4
+
5
+ before( :each ) do
6
+ YAML_Model.reset!
7
+ end
8
+
9
+ it "creates a method of the correct attribute name" do
10
+ User = Class.new( YAML_Model )
11
+ class User < YAML_Model
12
+ has :posts, Class.new( YAML_Model )
13
+ end
14
+ User.instance_methods.index( :posts ).should_not == nil
15
+ end
16
+
17
+ it "correctly references items that belong to it" do
18
+ User = Class.new( YAML_Model )
19
+ Post = Class.new( YAML_Model )
20
+ class Post < YAML_Model
21
+ type :user, User
22
+ init :user
23
+ end
24
+ class User < YAML_Model
25
+ has :posts, Post
26
+ end
27
+
28
+ user_a = User.create
29
+ user_b = User.create
30
+ user_c = User.create
31
+ post_a = Post.create( user_a )
32
+ post_b = Post.create( user_a )
33
+ post_c = Post.create( user_c )
34
+
35
+ user_a.posts.should == [ post_a, post_b ]
36
+ user_b.posts.should == []
37
+ user_c.posts.should == [ post_c ]
38
+ end
39
+
40
+ it "adds an add_ method when the relationship is many_to_many" do
41
+ Tag = Class.new( YAML_Model )
42
+ Post = Class.new( YAML_Model )
43
+ class Post < YAML_Model
44
+ has :tags, Tag, :many_to_many
45
+ end
46
+ Post.instance_methods.index( :add_tag ).should_not == nil
47
+ Tag.instance_methods.index( :add_post ).should == nil
48
+ end
49
+
50
+ it "handles many to many relationships seamlessly" do
51
+ Tag = Class.new( YAML_Model )
52
+ Post = Class.new( YAML_Model )
53
+ Post.has :tags, Tag, :many_to_many
54
+ Tag.has :posts, Post, :many_to_many
55
+
56
+ post_a = Post.create
57
+ post_b = Post.create
58
+ post_c = Post.create
59
+
60
+ tag_a = Tag.create
61
+ tag_b = Tag.create
62
+ tag_c = Tag.create
63
+
64
+ post_a.add_tag( tag_a )
65
+ post_a.add_tag( tag_b )
66
+ tag_b.add_post( post_c )
67
+
68
+ post_a.tags.sort.should == [ tag_a, tag_b ].sort
69
+ post_b.tags.should == []
70
+ post_c.tags.should == [ tag_b ]
71
+
72
+ tag_a.posts.should == [ post_a ]
73
+ tag_b.posts.sort.should == [ post_a, post_c ].sort
74
+ tag_c.posts.should == []
75
+ end
76
+
77
+ end
data/test/init.rb ADDED
@@ -0,0 +1,34 @@
1
+ require 'yaml-model'
2
+
3
+ describe YAML_Model, "::init" do
4
+
5
+ before( :each ) do
6
+ YAML_Model.reset!
7
+ end
8
+
9
+ it "runs the block it's given" do
10
+ $ran_it = false
11
+ Test = Class.new( YAML_Model )
12
+ class Test < YAML_Model
13
+ init do
14
+ $ran_it = true
15
+ end
16
+ end
17
+ $ran_it.should == false
18
+ Test.create
19
+ $ran_it.should == true
20
+ end
21
+
22
+ it "can set instance varibles inside blocks it's given" do
23
+ Test = Class.new( YAML_Model )
24
+ class Test < YAML_Model
25
+ type :name, String
26
+ init :name do
27
+ @name = "Bar"
28
+ end
29
+ end
30
+ test = Test.create( "Foo" )
31
+ test.name.should == "Bar"
32
+ end
33
+
34
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "yaml-model/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "yaml-model"
7
+ s.version = YAML_Model::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Clive Crous"]
10
+ s.email = ["clive@crous.co.za"]
11
+ s.homepage = "http://www.darkarts.co.za/yaml-model"
12
+ s.summary = %q{A NoSQL data model with data stored as YAML}
13
+ s.description = %q{A NoSQL data model with data stored as YAML}
14
+
15
+ s.add_development_dependency "bundler", ">= 1.0.0"
16
+ s.add_development_dependency "rspec", ">= 1.3.0"
17
+ s.add_development_dependency "rake", ">= 0.8.7"
18
+
19
+ s.files = `git ls-files`.split("\n")
20
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
21
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
22
+ s.require_paths = ["lib"]
23
+ end
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: yaml-model
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 1
9
+ version: 1.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Clive Crous
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-01-27 00:00:00 +02:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: bundler
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 0
30
+ - 0
31
+ version: 1.0.0
32
+ type: :development
33
+ prerelease: false
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: rspec
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ segments:
43
+ - 1
44
+ - 3
45
+ - 0
46
+ version: 1.3.0
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: rake
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ segments:
58
+ - 0
59
+ - 8
60
+ - 7
61
+ version: 0.8.7
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: *id003
65
+ description: A NoSQL data model with data stored as YAML
66
+ email:
67
+ - clive@crous.co.za
68
+ executables: []
69
+
70
+ extensions: []
71
+
72
+ extra_rdoc_files: []
73
+
74
+ files:
75
+ - .gitignore
76
+ - Gemfile
77
+ - Rakefile
78
+ - lib/yaml-model.rb
79
+ - lib/yaml-model/version.rb
80
+ - test/has.rb
81
+ - test/init.rb
82
+ - yaml-model.gemspec
83
+ has_rdoc: true
84
+ homepage: http://www.darkarts.co.za/yaml-model
85
+ licenses: []
86
+
87
+ post_install_message:
88
+ rdoc_options: []
89
+
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ hash: -961508909
98
+ segments:
99
+ - 0
100
+ version: "0"
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ hash: -961508909
107
+ segments:
108
+ - 0
109
+ version: "0"
110
+ requirements: []
111
+
112
+ rubyforge_project:
113
+ rubygems_version: 1.3.7
114
+ signing_key:
115
+ specification_version: 3
116
+ summary: A NoSQL data model with data stored as YAML
117
+ test_files: []
118
+