static_model 0.1.0 → 0.1.3
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/Manifest.txt +7 -1
- data/README.txt +1 -0
- data/config/hoe.rb +1 -1
- data/lib/static_model/active_record.rb +11 -0
- data/lib/static_model/associations.rb +82 -0
- data/lib/static_model/base.rb +23 -17
- data/lib/static_model/comparable.rb +14 -0
- data/lib/static_model/version.rb +1 -1
- data/lib/static_model.rb +7 -0
- data/test/authors.yml +10 -0
- data/test/books.yml +4 -0
- data/test/publishers.yml +5 -0
- data/test/test_helper.rb +66 -0
- data/test/test_static_model.rb +48 -6
- data/test/test_static_model_associations.rb +93 -0
- data/test/test_static_model_scope.rb +10 -0
- metadata +21 -4
data/Manifest.txt
CHANGED
@@ -7,10 +7,16 @@ config/hoe.rb
|
|
7
7
|
config/requirements.rb
|
8
8
|
lib/static_model.rb
|
9
9
|
lib/static_model/base.rb
|
10
|
+
lib/static_model/associations.rb
|
11
|
+
lib/static_model/active_record.rb
|
12
|
+
lib/static_model/comparable.rb
|
10
13
|
lib/static_model/errors.rb
|
11
14
|
lib/static_model/rails.rb
|
12
15
|
lib/static_model/version.rb
|
13
16
|
setup.rb
|
14
17
|
test/books.yml
|
18
|
+
test/authors.yml
|
19
|
+
test/publishers.yml
|
15
20
|
test/test_helper.rb
|
16
|
-
test/test_static_model.rb
|
21
|
+
test/test_static_model.rb
|
22
|
+
test/test_static_model_associations.rb
|
data/README.txt
CHANGED
data/config/hoe.rb
CHANGED
@@ -8,7 +8,7 @@ RUBYFORGE_PROJECT = 'quirkey' # The unix name for your project
|
|
8
8
|
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
9
9
|
DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
|
10
10
|
EXTRA_DEPENDENCIES = [
|
11
|
-
|
11
|
+
['activesupport', '>= 2.1.0']
|
12
12
|
] # An array of rubygem dependencies [name, version]
|
13
13
|
|
14
14
|
@config_file = "~/.rubyforge/user-config.yml"
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module StaticModel
|
2
|
+
module Associations
|
3
|
+
|
4
|
+
def self.included(klass)
|
5
|
+
klass.extend MacroMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module MacroMethods
|
9
|
+
|
10
|
+
def associations
|
11
|
+
@associations ||= {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def has_many(association_name, options = {})
|
15
|
+
self.associations[association_name.to_sym] = HasManyAssociation.new(self, association_name.to_sym, {:foreign_key => "#{self.to_s.foreign_key}"}.merge(options))
|
16
|
+
end
|
17
|
+
|
18
|
+
def belongs_to(association_name, options = {})
|
19
|
+
self.associations[association_name.to_sym] = BelongsToAssociation.new(self, association_name.to_sym, {:foreign_key => "#{association_name.to_s.foreign_key}"}.merge(options))
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
class Association
|
26
|
+
attr_reader :klass, :name, :options, :foreign_key
|
27
|
+
|
28
|
+
def initialize(klass, name, options = {})
|
29
|
+
@klass = klass
|
30
|
+
@name = name
|
31
|
+
@options = options
|
32
|
+
@reflection_klass_name = @options[:class_name] || @name.to_s.classify
|
33
|
+
@foreign_key = @options[:foreign_key]
|
34
|
+
define_association_methods
|
35
|
+
end
|
36
|
+
|
37
|
+
def reflection_klass
|
38
|
+
Object.const_get(@reflection_klass_name)
|
39
|
+
rescue
|
40
|
+
eval <<-EOT
|
41
|
+
class #{@reflection_klass_name}; end;
|
42
|
+
#{@reflection_klass_name}
|
43
|
+
EOT
|
44
|
+
end
|
45
|
+
|
46
|
+
def define_association_methods
|
47
|
+
raise 'Should only use descendants of Association'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class HasManyAssociation < Association
|
52
|
+
|
53
|
+
def define_association_methods
|
54
|
+
if reflection_klass.respond_to?(:scoped)
|
55
|
+
klass.module_eval <<-EOT
|
56
|
+
def #{name}
|
57
|
+
#{reflection_klass}.scoped(:conditions => {:#{foreign_key} => id})
|
58
|
+
end
|
59
|
+
EOT
|
60
|
+
else
|
61
|
+
klass.module_eval <<-EOT
|
62
|
+
def #{name}
|
63
|
+
#{reflection_klass}.send(:find_all_by_#{foreign_key}, id)
|
64
|
+
end
|
65
|
+
EOT
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class BelongsToAssociation < Association
|
71
|
+
|
72
|
+
def define_association_methods
|
73
|
+
klass.module_eval <<-EOT
|
74
|
+
def #{name}
|
75
|
+
#{reflection_klass}.send(:find, #{foreign_key})
|
76
|
+
end
|
77
|
+
EOT
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
data/lib/static_model/base.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
module StaticModel
|
2
2
|
class Base
|
3
|
-
|
3
|
+
include StaticModel::Associations
|
4
|
+
include StaticModel::ActiveRecord
|
5
|
+
include StaticModel::Comparable
|
6
|
+
|
4
7
|
@@load_path = File.join('config', 'data')
|
5
8
|
|
6
9
|
attr_reader :id
|
@@ -39,8 +42,7 @@ module StaticModel
|
|
39
42
|
end
|
40
43
|
|
41
44
|
def find_by_id(id)
|
42
|
-
|
43
|
-
record = @@records.detect {|r| r.id == id }
|
45
|
+
record = records.detect {|r| r.id == id }
|
44
46
|
raise(StaticModel::RecordNotFound, "Could not find record with id = #{id}") unless record
|
45
47
|
record
|
46
48
|
end
|
@@ -50,50 +52,54 @@ module StaticModel
|
|
50
52
|
end
|
51
53
|
|
52
54
|
def find_all
|
53
|
-
|
54
|
-
@@records
|
55
|
+
records
|
55
56
|
end
|
56
57
|
alias_method :all, :find_all
|
57
58
|
|
58
59
|
def find_first
|
59
|
-
|
60
|
-
@@records[0]
|
60
|
+
records[0]
|
61
61
|
end
|
62
62
|
alias_method :first, :find_first
|
63
63
|
|
64
64
|
def find_all_by(attribute, value)
|
65
|
-
|
66
|
-
records = @@records.find_all {|r| r.send(attribute) == value }
|
65
|
+
records.find_all {|r| r.send(attribute) == value }
|
67
66
|
end
|
68
67
|
|
69
68
|
def find_first_by(attribute, value)
|
70
|
-
|
71
|
-
records = @@records.find {|r| r.send(attribute) == value }
|
69
|
+
records.find {|r| r.send(attribute) == value }
|
72
70
|
end
|
73
71
|
|
74
72
|
def load(reload = false)
|
75
73
|
return if loaded? && !reload
|
76
74
|
raise(StaticModel::DataFileNotFound, "You must set a data file to load from") unless File.readable?(data_file)
|
77
75
|
records = YAML::load_file(data_file)
|
78
|
-
|
79
|
-
|
76
|
+
@records = records.dup.collect {|r| new(r) }
|
77
|
+
@loaded = true
|
80
78
|
end
|
81
79
|
|
82
80
|
def loaded?
|
83
|
-
|
81
|
+
@loaded ||= false
|
84
82
|
end
|
85
83
|
|
86
84
|
def data_file
|
87
|
-
|
85
|
+
@data_file ||= default_data_file_path
|
88
86
|
end
|
89
87
|
|
90
88
|
def set_data_file(file_path)
|
91
89
|
raise(StaticModel::DataFileNotFound, "Could not find data file #{file_path}") unless File.readable?(file_path)
|
92
|
-
|
90
|
+
@data_file = file_path
|
91
|
+
# force reload
|
92
|
+
@loaded = false
|
93
|
+
@records = nil
|
93
94
|
end
|
94
95
|
|
95
96
|
def count
|
96
|
-
|
97
|
+
records.length
|
98
|
+
end
|
99
|
+
|
100
|
+
def records
|
101
|
+
load
|
102
|
+
@records
|
97
103
|
end
|
98
104
|
|
99
105
|
protected
|
data/lib/static_model/version.rb
CHANGED
data/lib/static_model.rb
CHANGED
@@ -2,6 +2,13 @@ $:.unshift(File.dirname(__FILE__)) unless
|
|
2
2
|
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
3
|
|
4
4
|
require 'yaml'
|
5
|
+
|
6
|
+
require 'active_support/inflector'
|
7
|
+
require 'active_support/core_ext/string'
|
8
|
+
|
5
9
|
require 'static_model/errors'
|
10
|
+
require 'static_model/associations'
|
11
|
+
require 'static_model/active_record'
|
12
|
+
require 'static_model/comparable'
|
6
13
|
require 'static_model/base'
|
7
14
|
require 'static_model/rails'
|
data/test/authors.yml
ADDED
data/test/books.yml
CHANGED
@@ -2,17 +2,21 @@
|
|
2
2
|
- id: 1
|
3
3
|
title: The Omnivore's Dilemma
|
4
4
|
author: Michael Pollan
|
5
|
+
author_id: 1
|
5
6
|
genre: Non-Fiction
|
6
7
|
- id: 2
|
7
8
|
title: In Defense of Food
|
8
9
|
author: Michael Pollan
|
10
|
+
author_id: 1
|
9
11
|
genre: Non-Fiction
|
10
12
|
- id: 3
|
11
13
|
title: Omnivore (Of Man and Manta)
|
12
14
|
author: Piers Anthony
|
15
|
+
author_id: 2
|
13
16
|
genre: Fantasy
|
14
17
|
- id: 4
|
15
18
|
title: Choke
|
16
19
|
author: Chuck Palahniuk
|
20
|
+
author_id: 3
|
17
21
|
genre: Humor
|
18
22
|
|
data/test/publishers.yml
ADDED
data/test/test_helper.rb
CHANGED
@@ -1,9 +1,75 @@
|
|
1
1
|
require 'test/unit'
|
2
2
|
require 'rubygems'
|
3
3
|
require 'shoulda'
|
4
|
+
require 'mocha'
|
4
5
|
|
5
6
|
require File.dirname(__FILE__) + '/../lib/static_model'
|
6
7
|
|
7
8
|
class Book < StaticModel::Base
|
8
9
|
set_data_file File.join(File.dirname(__FILE__), 'books.yml')
|
9
10
|
end
|
11
|
+
|
12
|
+
unless defined?(ActiveRecord::Base)
|
13
|
+
module ActiveRecord
|
14
|
+
class Base
|
15
|
+
def self.scoped(*args)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Article < ActiveRecord::Base
|
22
|
+
end
|
23
|
+
|
24
|
+
class Publisher < StaticModel::Base
|
25
|
+
set_data_file File.join(File.dirname(__FILE__), 'publishers.yml')
|
26
|
+
|
27
|
+
has_many :authors
|
28
|
+
end
|
29
|
+
|
30
|
+
class Author < StaticModel::Base
|
31
|
+
set_data_file File.join(File.dirname(__FILE__), 'authors.yml')
|
32
|
+
has_many :books
|
33
|
+
has_many :articles
|
34
|
+
belongs_to :publisher
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
class Test::Unit::TestCase
|
41
|
+
|
42
|
+
def assert_all(collection)
|
43
|
+
collection.each do |one|
|
44
|
+
assert yield(one), "#{one} is not true"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def assert_any(collection, &block)
|
50
|
+
has = collection.any? do |one|
|
51
|
+
yield(one)
|
52
|
+
end
|
53
|
+
assert has
|
54
|
+
end
|
55
|
+
|
56
|
+
def assert_ordered(array_of_ordered_items, message = nil, &block)
|
57
|
+
raise "Parameter must be an Array" unless array_of_ordered_items.is_a?(Array)
|
58
|
+
message ||= "Items were not in the correct order"
|
59
|
+
i = 0
|
60
|
+
# puts array_of_ordered_items.length
|
61
|
+
while i < (array_of_ordered_items.length - 1)
|
62
|
+
# puts "j"
|
63
|
+
a, b = array_of_ordered_items[i], array_of_ordered_items[i+1]
|
64
|
+
comparison = yield(a,b)
|
65
|
+
# raise "#{comparison}"
|
66
|
+
assert(comparison, message + " - #{a}, #{b}")
|
67
|
+
i += 1
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def assert_set_of(klass, set)
|
72
|
+
assert set.respond_to?(:each), "#{set} is not a set (does not include Enumerable)"
|
73
|
+
assert_all(set) {|a| a.is_a?(klass) }
|
74
|
+
end
|
75
|
+
end
|
data/test/test_static_model.rb
CHANGED
@@ -40,10 +40,51 @@ class TestStaticModel < Test::Unit::TestCase
|
|
40
40
|
assert_equal @book.inspect, @book.to_s
|
41
41
|
end
|
42
42
|
end
|
43
|
+
|
44
|
+
context "comparing" do
|
45
|
+
|
46
|
+
should "be equal to an instance of the same class with same id" do
|
47
|
+
assert_equal @book, Book.new(book_params)
|
48
|
+
end
|
49
|
+
|
50
|
+
should "not be equal to an instance with the same class with different ids" do
|
51
|
+
assert_not_equal Book[1], @book
|
52
|
+
end
|
53
|
+
|
54
|
+
should "not be equal to an instance with different classes and the same ids" do
|
55
|
+
assert_not_equal Book[1], Author[1]
|
56
|
+
end
|
57
|
+
end
|
43
58
|
|
44
59
|
end
|
45
60
|
|
46
61
|
context "on the class" do
|
62
|
+
context "set data file" do
|
63
|
+
context "After the class is defined" do
|
64
|
+
|
65
|
+
setup do
|
66
|
+
@book = Book.find(1)
|
67
|
+
@author = Author.find(1)
|
68
|
+
@original_data_file = Book.data_file
|
69
|
+
@data_file = File.join(File.dirname(__FILE__), 'authors.yml')
|
70
|
+
Book.set_data_file @data_file
|
71
|
+
@new_book = Book.find(1)
|
72
|
+
end
|
73
|
+
|
74
|
+
should "set the @data_file" do
|
75
|
+
assert_equal @data_file, Book.data_file
|
76
|
+
end
|
77
|
+
|
78
|
+
should "reload with next find" do
|
79
|
+
assert @author.attributes, @new_book.attributes
|
80
|
+
end
|
81
|
+
|
82
|
+
teardown do
|
83
|
+
Book.set_data_file @original_data_file
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
47
88
|
context "find" do
|
48
89
|
|
49
90
|
context "with an integer" do
|
@@ -70,13 +111,13 @@ class TestStaticModel < Test::Unit::TestCase
|
|
70
111
|
end
|
71
112
|
end
|
72
113
|
end
|
73
|
-
|
114
|
+
|
74
115
|
context "[]" do
|
75
116
|
should "be an alias for find by id" do
|
76
117
|
assert_equal Book.find(1), Book[1]
|
77
118
|
end
|
78
119
|
end
|
79
|
-
|
120
|
+
|
80
121
|
context "find(:all)" do
|
81
122
|
should "be an alias for find_all" do
|
82
123
|
assert_equal Book.find_all, Book.find(:all)
|
@@ -195,15 +236,14 @@ class TestStaticModel < Test::Unit::TestCase
|
|
195
236
|
assert_equal Book.find_all_by(:genre, 'Non-Fiction'), Book.find_all_by_genre('Non-Fiction')
|
196
237
|
end
|
197
238
|
end
|
198
|
-
|
239
|
+
|
199
240
|
context "count" do
|
200
241
|
should "return the count of all records" do
|
201
242
|
assert_equal Book.all.length, Book.count
|
202
243
|
end
|
203
244
|
end
|
204
|
-
|
245
|
+
|
205
246
|
end
|
206
|
-
|
207
247
|
end
|
208
248
|
end
|
209
249
|
|
@@ -211,4 +251,6 @@ class TestStaticModel < Test::Unit::TestCase
|
|
211
251
|
def book_params
|
212
252
|
{:id => 15, :title => 'Lord of the Rings', :author => 'J.R. Tolkien', :genre => 'Fantasy'}
|
213
253
|
end
|
214
|
-
|
254
|
+
|
255
|
+
|
256
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
class TestStaticModelAssociations < Test::Unit::TestCase
|
4
|
+
|
5
|
+
context "a static model class" do
|
6
|
+
|
7
|
+
context "with a has many association" do
|
8
|
+
context "to another static model" do
|
9
|
+
# Author has many books
|
10
|
+
setup do
|
11
|
+
@author = Author.find(1)
|
12
|
+
end
|
13
|
+
|
14
|
+
should "respond to association name" do
|
15
|
+
assert @author.books
|
16
|
+
end
|
17
|
+
|
18
|
+
should "return an array of association instances if association is a StaticModel" do
|
19
|
+
assert_set_of Book, @author.books
|
20
|
+
end
|
21
|
+
|
22
|
+
should "find books by foreign_key" do
|
23
|
+
assert_equal Book.find_all_by_author_id(@author.id), @author.books
|
24
|
+
end
|
25
|
+
|
26
|
+
should "add association to associations" do
|
27
|
+
assert Author.associations.has_key?(:books)
|
28
|
+
end
|
29
|
+
|
30
|
+
should "have HasManyAssociation in associations" do
|
31
|
+
assert Author.associations[:books].is_a?(StaticModel::Associations::HasManyAssociation)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "to an active record model" do
|
36
|
+
setup do
|
37
|
+
@author = Author.find(1)
|
38
|
+
Article.expects(:scoped).returns([Article.new, Article.new])
|
39
|
+
end
|
40
|
+
|
41
|
+
should "respond to association name" do
|
42
|
+
assert @author.articles
|
43
|
+
end
|
44
|
+
|
45
|
+
should "return an array of association instances if association is a StaticModel" do
|
46
|
+
assert_set_of Article, @author.articles
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
context "with a belongs to association" do
|
54
|
+
context "to another static model" do
|
55
|
+
# Author belongs to publisher
|
56
|
+
setup do
|
57
|
+
@author = Author.find(1)
|
58
|
+
end
|
59
|
+
|
60
|
+
should "respond to association name" do
|
61
|
+
assert @author.publisher
|
62
|
+
end
|
63
|
+
|
64
|
+
should "return a single instance" do
|
65
|
+
assert @author.publisher.is_a?(Publisher)
|
66
|
+
end
|
67
|
+
|
68
|
+
should "find publisher by foreign key" do
|
69
|
+
assert_equal Publisher.find(1), @author.publisher
|
70
|
+
end
|
71
|
+
|
72
|
+
should "add association to associations" do
|
73
|
+
assert Author.associations.has_key?(:publisher)
|
74
|
+
end
|
75
|
+
|
76
|
+
should "have BelongsTo association in associations" do
|
77
|
+
assert Author.associations[:publisher].is_a?(StaticModel::Associations::BelongsToAssociation)
|
78
|
+
end
|
79
|
+
|
80
|
+
context "when foreign key is nil" do
|
81
|
+
setup do
|
82
|
+
@author = Author.find(2)
|
83
|
+
end
|
84
|
+
|
85
|
+
should "respond to association name and return nil" do
|
86
|
+
assert_nil @author.publisher
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: static_model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Quint
|
@@ -9,10 +9,19 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-08-01 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hoe
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.7.0
|
24
|
+
version:
|
16
25
|
description: ActiveRecord like functionalities for reading from YAML with a simple class implementation
|
17
26
|
email:
|
18
27
|
- aaron@quirkey.com
|
@@ -35,13 +44,19 @@ files:
|
|
35
44
|
- config/requirements.rb
|
36
45
|
- lib/static_model.rb
|
37
46
|
- lib/static_model/base.rb
|
47
|
+
- lib/static_model/associations.rb
|
48
|
+
- lib/static_model/active_record.rb
|
49
|
+
- lib/static_model/comparable.rb
|
38
50
|
- lib/static_model/errors.rb
|
39
51
|
- lib/static_model/rails.rb
|
40
52
|
- lib/static_model/version.rb
|
41
53
|
- setup.rb
|
42
54
|
- test/books.yml
|
55
|
+
- test/authors.yml
|
56
|
+
- test/publishers.yml
|
43
57
|
- test/test_helper.rb
|
44
58
|
- test/test_static_model.rb
|
59
|
+
- test/test_static_model_associations.rb
|
45
60
|
has_rdoc: true
|
46
61
|
homepage: http://quirkey.rubyforge.org
|
47
62
|
post_install_message: ""
|
@@ -72,3 +87,5 @@ summary: ActiveRecord like functionalities for reading from YAML with a simple c
|
|
72
87
|
test_files:
|
73
88
|
- test/test_helper.rb
|
74
89
|
- test/test_static_model.rb
|
90
|
+
- test/test_static_model_associations.rb
|
91
|
+
- test/test_static_model_scope.rb
|