ygg 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/README.rdoc +57 -0
  2. data/lib/ygg.rb +3 -222
  3. data/lib/ygg/base.rb +224 -0
  4. data/lib/ygg/version.rb +1 -1
  5. metadata +4 -2
@@ -0,0 +1,57 @@
1
+ = Ygg
2
+
3
+ Lightweight YAML persistence solution with sofisticated ORM-class models and relationships.
4
+
5
+ == Installation
6
+
7
+ gem install ygg
8
+
9
+ == Usage
10
+
11
+ require "ygg"
12
+
13
+ class User < Ygg::Model
14
+ attr_accessor :name, :pass
15
+ end
16
+
17
+ class Article < Ygg::Model
18
+ attr_accessor :title, :content
19
+ end
20
+
21
+ Ygg.load "data.yaml"
22
+
23
+ user = User.create :index => "johnr",
24
+ :name => "John Robertson",
25
+ :pass => "secret"
26
+
27
+ article = Article.create :index => "first-ygg"
28
+ article.title = "Using Ygg for the first time"
29
+ article.content = "The API is inspired in classic ORMs like ActiveRecord"
30
+
31
+ user >> article # This declaration creations a relationships between the user and the article
32
+
33
+ Ygg.save
34
+
35
+ And then for obtaining all articles belonging to "johnr"
36
+
37
+ # require and Model declarations here
38
+
39
+ Ygg.load "data.yaml"
40
+
41
+ puts User.get("johnr") >= Article
42
+
43
+ Further documentation on functions will be added when the core reaches some stability.
44
+
45
+ = License
46
+
47
+ (The MIT License)
48
+
49
+ Copyright © 2011:
50
+
51
+ * Xavier Via (http://germino.com.ar)
52
+
53
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ‘Software’), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
54
+
55
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
56
+
57
+ THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/lib/ygg.rb CHANGED
@@ -1,224 +1,5 @@
1
- require "yaml"
2
- require "singleton"
1
+ require "ygg/base"
3
2
 
4
- module Ygg
3
+ include Ygg::Delegator
5
4
 
6
- # Mappers for simplicity
7
- def self.load(file)
8
- Ygg::DSL.instance.eagerly file
9
- end
10
-
11
- def self.save
12
- Ygg::DSL.instance.save
13
- end
14
-
15
- def self.rel(*args)
16
- Ygg::DSL.instance.rel *args
17
- end
18
-
19
- module Delegator
20
- def delegate(target, *methods)
21
- methods.each do |method|
22
- self.class.send :define_method, method do |*args, &block|
23
- target.send method, *args, &block
24
- end
25
- end
26
- end
27
- end
28
-
29
- class Relationship
30
- attr_accessor :source
31
- attr_accessor :target
32
-
33
- def initialize(source, target)
34
- @source = source
35
- @target = target
36
-
37
- short = Ygg::DSL.instance.data
38
- short[:relationship] ||= []
39
- short[:relationship] << self
40
- end
41
- end
42
-
43
- class DSL
44
- include Singleton
45
-
46
- attr_accessor :data
47
- attr_accessor :source
48
-
49
- def eagerly(source)
50
- @source = source
51
- if File.exists? @source
52
- @data = YAML.load_file @source
53
- else
54
- @data = {}
55
- end
56
- end
57
-
58
- def save # Maybe get it better
59
- source = @source if @source
60
- unless source
61
- raise "There's already a file named 'ygg.yaml'." if File.exists? "ygg.yaml"
62
- source = "ygg.yaml"
63
- end
64
-
65
- File.open source, "w" do |file|
66
- file.write YAML.dump @data
67
- end
68
- end
69
-
70
- def record(model, id)
71
- model_sym = model.to_s.downcase.to_sym
72
- @data[model_sym][id]
73
- end
74
-
75
- def add(resource, son)
76
- Ygg::Relationship.new resource, son
77
- end
78
-
79
- def _source(relation, resource, type = nil)
80
- if relation.source == resource
81
- if type == :all
82
- return relation.target
83
- elsif relation.target.class == type
84
- return relation.target
85
- end
86
- end
87
- return false
88
- end
89
-
90
- def _target(relation, resource, type = nil)
91
- if relation.target == resource
92
- if type == :all
93
- return relation.source
94
- elsif relation.source.class == type
95
- return relation.source
96
- end
97
- end
98
- return false
99
- end
100
-
101
- def rel(resource, options = {})
102
- options[:as] ||= :any
103
- options[:type] ||= :all
104
- result = []
105
- @data[:relationship].each do |relation|
106
- args = [relation, resource, options[:type]]
107
- case options[:as]
108
- when :any
109
- if res = _source(*args)
110
- result << res
111
- elsif res = _target(*args)
112
- result << res
113
- end
114
- when :source
115
- if res = _source(*args)
116
- result << res
117
- end
118
- when :target
119
- if res = _target(*args)
120
- result << res
121
- end
122
- end
123
- end
124
- result
125
- end
126
- end
127
-
128
- class Model
129
- # Define methods for retrieving relations and
130
- # creating relations
131
-
132
- attr_accessor :index
133
-
134
- # Instance methods
135
- def >>(resource)
136
- Ygg::DSL.instance.add self, resource
137
- end
138
-
139
- def <<(resource)
140
- Ygg::DSL.instance.add resource, self
141
- end
142
-
143
- def %(type)
144
- if type == :all
145
- Ygg::DSL.instance.rel self
146
- elsif type.kind_of? Class
147
- Ygg::DSL.instance.rel self, :type => type
148
- end
149
- end
150
-
151
- def >=(type)
152
- if type == :all
153
- Ygg::DSL.instance.rel self, :as => :source
154
- elsif type.kind_of? Class
155
- Ygg::DSL.instance.rel self, :as => :source, :type => type
156
- end
157
- end
158
-
159
- def <=(type)
160
- if type == :all
161
- Ygg::DSL.instance.rel self, :as => :target
162
- elsif type.kind_of? Class
163
- Ygg::DSL.instance.rel self, :as => :target, :type => type
164
- end
165
- end
166
-
167
- # Register this datus in the @data
168
- def initialize(index)
169
- Ygg::DSL.instance.data ||= {}
170
- Ygg::DSL.instance.data[Ygg.symbolize(self)] ||= {}
171
- if index.kind_of? String
172
- Ygg::DSL.instance.data[Ygg.symbolize(self)][index] = self
173
- @index = index
174
- elsif index.kind_of? Hash
175
- raise "Index missing" unless index[:index]
176
- index.each do |key, value|
177
- self.send "#{key}=".to_sym, value
178
- end
179
- end
180
- end
181
-
182
- # Class methods
183
- def self.create(data)
184
- if data.kind_of? Hash
185
- raise "Index missing" unless data[:index]
186
- index = data[:index]
187
- elsif data.kind_of? String
188
- index = data
189
- end
190
- instance = self.new index
191
-
192
- if data.kind_of? Hash
193
- data.each do |key, value|
194
- instance.send "#{key}=".to_sym, value
195
- end
196
- end
197
- Ygg::DSL.instance.save
198
- instance
199
- end
200
-
201
- def self.all
202
- Ygg::DSL.instance.data[self.to_s.downcase.to_sym] ||= {}
203
- end
204
-
205
- def self.get(index)
206
- Ygg::DSL.instance.record(self, index)
207
- end
208
-
209
- def self.related_to(datus, as = nil)
210
- options = {}
211
- options[:type] = self
212
- options[:as] = as if as
213
- Ygg::DSL.instance.rel datus, options
214
- end
215
- end
216
-
217
- def self.symbolize(object)
218
- object.class.to_s.downcase.to_sym
219
- end
220
- end
221
-
222
- #include Ygg::Delegator
223
-
224
- #delegate Ygg::DSL, :save, :record, :relateds
5
+ delegate Ygg, :save, :data, :load
@@ -0,0 +1,224 @@
1
+ require "yaml"
2
+
3
+ module Ygg
4
+ @@data
5
+ @@source
6
+
7
+ def self.load(source = "ygg.yaml", &block)
8
+
9
+ if source.kind_of? Symbol
10
+ if File.exists? "#{source}.yml"
11
+ source = "#{source}.yml"
12
+ else
13
+ source = "#{source}.yaml"
14
+ end
15
+ end
16
+ @@source ||= source if source == "ygg.yaml"
17
+ @@source = source if source != "ygg.yaml"
18
+
19
+ @@data = {}
20
+ @@data = YAML.load_file @@source if File.exists? @@source
21
+
22
+ @@data.each do |key, model|
23
+ model.each do |resource|
24
+ resource.loading! if resource.respond_to? :loading!
25
+ end if model.kind_of? Array
26
+ end
27
+
28
+ if block; yield; self.save; self.close; end
29
+ end
30
+
31
+ def self.save
32
+ @@data ||= {}
33
+ @@data.each do |key, model|
34
+ model.each do |resource|
35
+ resource._finalize! if resource.respond_to? :_finalize!
36
+ end if model.kind_of? Array
37
+ end
38
+
39
+ File.open @@source, "w" do |file|
40
+ file.write YAML.dump(@@data)
41
+ end
42
+ end
43
+
44
+ def self.close; @@data = nil; @@source; end
45
+
46
+ def self.data; @@data ||= {}; end
47
+
48
+ def self.symbolize(res)
49
+ return res.to_s.downcase.to_sym if res.kind_of? Class
50
+ res.class.to_s.downcase.to_sym
51
+ end
52
+
53
+ class Model
54
+ @@validator = [/(.*)/, [:index]]
55
+
56
+ def initialize(*args)
57
+ Ygg.data[Ygg.symbolize(self)] ||= []
58
+ Ygg.data[Ygg.symbolize(self)] << self
59
+ @created_at ||= Time.now if respond_to? :created_at
60
+ @updated_at ||= Time.now if respond_to? :updated_at
61
+
62
+ if data = args.shift
63
+ if data.kind_of? Hash
64
+ data.each {|k,v| self.send(:"#{k}=", v) }
65
+ elsif data.kind_of? String
66
+ validator = self.class.validator
67
+ if matches = data.match(validator[0])
68
+ validator[1].each_index do |i|
69
+ self.send :"_#{validator[1][i]}=", matches[i+1]
70
+ end
71
+ else
72
+ raise Ygg::InvalidInitializor, "#{data} does not match the validation regexp for #{self.class}"
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ # Instance methods : Defaults
79
+ def _finalize!; finalize! if respond_to? :finalize!; end
80
+ def _loading!; loading! if respond_to? :loading!; end
81
+ def destroy
82
+ Ygg.data[Ygg.symbolize(self)].delete self
83
+ # Destroy all Links
84
+ end
85
+ def _id
86
+ Ygg.data[Ygg.symbolize(self)].index self
87
+ end
88
+
89
+ # Instance methods : Links
90
+ def &(res)
91
+ Link.new :source => self, :target => res
92
+ end
93
+ def >(arg); targets arg; end
94
+ def <(arg); sources arg; end
95
+ def *(arg); links arg; end
96
+ def links(arg = nil); targets(arg) + sources(arg); end
97
+
98
+ def targets(arg = nil) # Test
99
+ links = Link.all.by_source self
100
+ return [] if links.kind_of? Array and links.empty?
101
+ links = [links] unless links.kind_of? Array
102
+ result = []
103
+ links.each do |link|
104
+ if arg
105
+ if arg.kind_of? Class
106
+ result << link.target if link.target.class == arg
107
+ else
108
+ result << link.target if link.info == arg
109
+ end
110
+ else; result << link.target; end
111
+ end
112
+ result
113
+ end
114
+
115
+ def sources(arg = nil) # Test
116
+ links = Link.all.by_target self
117
+ return [] if links.kind_of? Array and links.empty?
118
+ links = [links] unless links.kind_of? Array
119
+ result = []
120
+ links.each do |link|
121
+ if arg
122
+ if arg.kind_of? Class
123
+ result << link.source if link.source.class == arg
124
+ else
125
+ result << link.source if link.info == arg
126
+ end
127
+ else; result << link.source; end
128
+ end
129
+ result
130
+ end
131
+
132
+ def link_with(resource) # Test
133
+ links = Link.all.by_source self
134
+ return nil if links.kind_of? Array and links.empty?
135
+ links = [links] unless links.kind_of? Array
136
+ result = []
137
+ links.each do |link|
138
+ result << link if link.target == resource
139
+ end
140
+
141
+ return false if result.length == 0
142
+ return result[0] if result.length == 1
143
+ return result
144
+ end
145
+
146
+ # Class methods : Shorthands
147
+ def self.all; Ygg.data[Ygg.symbolize(self)]; end
148
+ def self.validator; @@validator; end
149
+
150
+ # Class methods : Metamethods
151
+ def self.timestamps!; attr_accessor :created_at, :updated_at; end
152
+
153
+ def self.key(*args)
154
+ attr_reader *args
155
+ args.each do |arg|
156
+ class_eval <<-_EOE
157
+ def _#{arg}=(v)
158
+ @#{arg} = v
159
+ end
160
+
161
+ def _#{arg}_hook=(v)
162
+ @updated_at = Time.now if respond_to? :updated_at
163
+ end
164
+
165
+ def #{arg}=(v)
166
+ self._#{arg}_hook = v
167
+ self._#{arg} = v
168
+ end
169
+ _EOE
170
+ end
171
+ end
172
+ end
173
+
174
+ class Link < Model
175
+ attr_accessor :source, :target, :info
176
+ def &(data); @info = data; end
177
+ end
178
+
179
+ class InvalidInitializor < RuntimeError; end
180
+
181
+ module Delegator
182
+ def delegate(target, *methods)
183
+ methods.each do |method|
184
+ self.class.send :define_method, method do |*a, &b|
185
+ target.send method, *a, &b
186
+ end
187
+ end
188
+ end
189
+ end
190
+ end
191
+
192
+ class Array
193
+ def method_missing(x, *args)
194
+ if matches = x.to_s.match(/^sort_by_(.+)$/)
195
+ key = matches[1].to_sym
196
+ self.sort_by { |x| x.send(key) }
197
+
198
+ elsif matches = x.to_s.match(/^by_(.+)$/) # Extend with regexps
199
+ key = matches[1].to_sym
200
+
201
+ if to_find = args.shift
202
+ result = []
203
+ self.each do |res|
204
+ if res.respond_to? key
205
+ datus = res.send key
206
+ result << res if datus == to_find
207
+ end
208
+ end
209
+ return [] if result.length == 0
210
+ return result[0] if result.length == 1
211
+ return result
212
+
213
+ else
214
+ self.send(:"sort_by_#{key}")[0] unless empty?
215
+ end
216
+
217
+ return []
218
+ end
219
+ end
220
+ end
221
+
222
+ #include Ygg::Delegator
223
+
224
+ #delegate Ygg, :save, :data, :load
@@ -1,3 +1,3 @@
1
1
  module Ygg
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ygg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-05-30 00:00:00.000000000 -03:00
12
+ date: 2011-06-03 00:00:00.000000000 -03:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
  description: Pure Ruby persistence solution
@@ -21,8 +21,10 @@ extra_rdoc_files: []
21
21
  files:
22
22
  - .gitignore
23
23
  - Gemfile
24
+ - README.rdoc
24
25
  - Rakefile
25
26
  - lib/ygg.rb
27
+ - lib/ygg/base.rb
26
28
  - lib/ygg/version.rb
27
29
  - ygg.gemspec
28
30
  has_rdoc: true