yaml-model 1.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.
- data/.gitignore +6 -0
- data/Gemfile +4 -0
- data/Rakefile +9 -0
- data/lib/yaml-model.rb +173 -0
- data/lib/yaml-model/version.rb +3 -0
- data/test/has.rb +77 -0
- data/test/init.rb +34 -0
- data/yaml-model.gemspec +23 -0
- metadata +118 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
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
|
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
|
data/yaml-model.gemspec
ADDED
@@ -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
|
+
|