static_model 0.1.0 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -13,6 +13,7 @@ ActiveRecord like functionalities for reading from YAML with a simple class impl
13
13
  == REQUIREMENTS:
14
14
 
15
15
  YAML
16
+ activesupport >= 2.1.0
16
17
 
17
18
  == INSTALL:
18
19
 
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
- # ['activesupport', '>= 1.3.1']
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,11 @@
1
+ module StaticModel
2
+ module ActiveRecord
3
+ # Stubbing out ActiveRecord methods so that associations work
4
+
5
+ def new_record?
6
+ false
7
+ end
8
+
9
+
10
+ end
11
+ end
@@ -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
@@ -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
- load
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
- load
54
- @@records
55
+ records
55
56
  end
56
57
  alias_method :all, :find_all
57
58
 
58
59
  def find_first
59
- load
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
- load
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
- load
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
- @@records = records.dup.collect {|r| new(r) }
79
- @@loaded = true
76
+ @records = records.dup.collect {|r| new(r) }
77
+ @loaded = true
80
78
  end
81
79
 
82
80
  def loaded?
83
- @@loaded ||= false
81
+ @loaded ||= false
84
82
  end
85
83
 
86
84
  def data_file
87
- @@data_file ||= default_data_file_path
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
- @@data_file = file_path
90
+ @data_file = file_path
91
+ # force reload
92
+ @loaded = false
93
+ @records = nil
93
94
  end
94
95
 
95
96
  def count
96
- @@records.length
97
+ records.length
98
+ end
99
+
100
+ def records
101
+ load
102
+ @records
97
103
  end
98
104
 
99
105
  protected
@@ -0,0 +1,14 @@
1
+ module StaticModel
2
+ module Comparable
3
+ include ::Comparable
4
+
5
+ def <=>(other)
6
+ if self.class == other.class
7
+ self.id <=> other.id
8
+ else
9
+ -1
10
+ end
11
+ end
12
+
13
+ end
14
+ end
@@ -2,7 +2,7 @@ module StaticModel #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 1
5
- TINY = 0
5
+ TINY = 3
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
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
@@ -0,0 +1,10 @@
1
+ ---
2
+ - id: 1
3
+ publisher_id: 1
4
+ name: Michael Pollan
5
+ - id: 2
6
+ publisher_id:
7
+ name: Piers Anthony
8
+ - id: 3
9
+ publisher_id: 2
10
+ name: Chuck Palahniuk
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
 
@@ -0,0 +1,5 @@
1
+ ---
2
+ - id: 1
3
+ name: Phaidon
4
+ - id: 2
5
+ name: Penguin
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
@@ -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
- end
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
@@ -0,0 +1,10 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestStaticModelScope < Test::Unit::TestCase
4
+
5
+ context "a static model class" do
6
+ context "A class with scope" do
7
+
8
+ end
9
+ end
10
+ 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.0
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-07-09 00:00:00 -04:00
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