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 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