fauxsql 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -19,3 +19,5 @@ rdoc
19
19
  pkg
20
20
 
21
21
  ## PROJECT::SPECIFIC
22
+ .bundle
23
+ ruby-1.9.1-p378/
data/Gemfile CHANGED
@@ -18,5 +18,5 @@ gem 'dm-validations', :git => 'git://github.com/datamapper/
18
18
  gem 'dm-aggregates', :git => 'git://github.com/datamapper/dm-aggregates.git'
19
19
  gem 'dm-constraints', :git => 'git://github.com/datamapper/dm-constraints.git'
20
20
  gem 'dm-observer', :git => 'git://github.com/datamapper/dm-observer.git'
21
- gem "dm-core", :git => "git://github.com/collin/dm-core.git", "branch" => "next"
21
+ gem "dm-core", :git => "git://github.com/datamapper/dm-core.git", "branch" => "next"
22
22
  gem "datamapper"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.2.0
data/fauxsql.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{fauxsql}
8
- s.version = "0.1.2"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Collin Miller"]
12
- s.date = %q{2010-04-20}
12
+ s.date = %q{2010-05-06}
13
13
  s.description = %q{And description}
14
14
  s.email = %q{collintmiller@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -27,12 +27,16 @@ Gem::Specification.new do |s|
27
27
  "fauxsql.gemspec",
28
28
  "lib/fauxsql.rb",
29
29
  "lib/fauxsql/attribute_list.rb",
30
+ "lib/fauxsql/attribute_manymany.rb",
30
31
  "lib/fauxsql/attribute_map.rb",
31
32
  "lib/fauxsql/attribute_wrapper.rb",
33
+ "lib/fauxsql/attributes.rb",
32
34
  "lib/fauxsql/dereferenced_attribute.rb",
33
35
  "lib/fauxsql/dsl.rb",
34
36
  "lib/fauxsql/list_wrapper.rb",
37
+ "lib/fauxsql/manymany_wrapper.rb",
35
38
  "lib/fauxsql/map_wrapper.rb",
39
+ "lib/fauxsql/options.rb",
36
40
  "test/helper.rb",
37
41
  "test/test_fauxsql.rb"
38
42
  ]
@@ -5,29 +5,46 @@ module Fauxsql
5
5
  def <<(attribute)
6
6
  super Fauxsql.dereference_fauxsql_attribute(attribute)
7
7
  end
8
-
8
+
9
9
  def [] index
10
10
  Fauxsql.resolve_fauxsql_attribute super(index)
11
11
  end
12
-
12
+
13
13
  def first
14
14
  self[0]
15
15
  end
16
-
16
+
17
17
  def last
18
18
  self[length - 1]
19
19
  end
20
-
20
+
21
+ def all
22
+ map{|item| Fauxsql.resolve_fauxsql_attribute item }
23
+ end
24
+
21
25
  def equals list
22
26
  map_resolved == list
23
27
  end
24
28
 
25
- def map_resolved
26
- map = []
27
- each_with_index do |item, index|
28
- map[index] = self[index]
29
- end
30
- map
31
- end
29
+ def each
30
+ super{|item| yield(Fauxsql.resolve_fauxsql_attribute(item)) }
31
+ end
32
+
33
+ def each_with_index
34
+ super{|item, index| yield(Fauxsql.resolve_fauxsql_attribute(item), index) }
35
+ end
36
+
37
+ def -(others)
38
+ others = others.map{|other| Fauxsql.dereference_fauxsql_attribute(other).hash }
39
+ reject!{|one| others.include?(one.hash) }
40
+ self
41
+ end
42
+
43
+ # Always being not eql is expensive
44
+ # TODO make this work without this hack
45
+ def eql?(other)
46
+ return false
47
+ end
48
+
32
49
  end
33
50
  end
@@ -0,0 +1,11 @@
1
+ module Fauxsql
2
+ # AttributeMap is an Hash that dereferences and resolves fauxsql attributes
3
+ # when setting/reading members in the Hash
4
+ class AttributeManymany < AttributeList
5
+ # Always being not eql is expensive
6
+ # TODO make this work without this hack
7
+ def eql?(other)
8
+ return false
9
+ end
10
+ end
11
+ end
@@ -1,18 +1,31 @@
1
1
  module Fauxsql
2
2
  # AttributeMap is an Hash that dereferences and resolves fauxsql attributes
3
3
  # when setting/reading members in the Hash
4
+ def self.dereference_fauxsql_key(key)
5
+ real_key = Fauxsql.dereference_fauxsql_attribute(key)
6
+ if (real_key.is_a? Fauxsql::DereferencedAttribute)
7
+ real_key = real_key.hash
8
+ end
9
+ real_key
10
+ end
11
+
4
12
  class AttributeMap < Hash
5
- # We dereference and resolve the key because in Ruby _any_ object
13
+ # We dereference and resolve the key because in Ruby not _any_ object
6
14
  # can be a hash key. Even a DataMapper record.
7
15
  def []= key, value
8
- real_key = Fauxsql.dereference_fauxsql_attribute(key)
16
+ real_key = Fauxsql.dereference_fauxsql_key(key)
9
17
  real_value = Fauxsql.dereference_fauxsql_attribute(value)
10
- super real_key.hash, real_value
18
+ super real_key, real_value
11
19
  end
12
20
 
13
21
  def [] key
14
- real_key = Fauxsql.dereference_fauxsql_attribute(key)
15
- Fauxsql.resolve_fauxsql_attribute super(real_key.hash)
22
+ real_key = Fauxsql.dereference_fauxsql_key(key)
23
+ Fauxsql.resolve_fauxsql_attribute super(real_key)
24
+ end
25
+
26
+ def delete key
27
+ real_key = Fauxsql.dereference_fauxsql_key(key)
28
+ super(real_key)
16
29
  end
17
30
 
18
31
  def each(&block)
@@ -30,7 +43,7 @@ module Fauxsql
30
43
  end
31
44
 
32
45
  def resolve_key(key)
33
- if key.respond_to?(:match) && key.match(/^.+Fauxsql::DereferencedAttribute.+@klass.+@lookup_key.+$/)
46
+ if key.respond_to?(:match) && key.match(/^.+Fauxsql::DereferencedAttribute.+@lookup_key.+$/)
34
47
  Fauxsql.resolve_fauxsql_attribute Fauxsql::DereferencedAttribute.load(key)
35
48
  else
36
49
  key
@@ -41,11 +54,10 @@ module Fauxsql
41
54
  Fauxsql.resolve_fauxsql_attribute value
42
55
  end
43
56
 
57
+ # Always being not eql is expensive
58
+ # TODO make this work without this hack
44
59
  def eql?(other)
45
60
  return false
46
- raise [self, other.inspect].inspect
47
61
  end
48
-
49
-
50
62
  end
51
63
  end
@@ -1,20 +1,31 @@
1
1
  module Fauxsql
2
2
  class AttributeWrapper
3
+ class MissingOptions < ArgumentError
4
+ def initialize(missing, options)
5
+ super "Missing option :#{missing} in #{options.inspect}"
6
+ end
7
+ end
3
8
  extend ActiveSupport::Concern
4
9
  attr_reader:attribute
5
10
  attr_reader:record
6
11
  attr_reader:name
12
+ attr_reader:options
7
13
 
8
- def initialize(attribute, record, name)
9
- @attribute, @record, @name = attribute, record, name
14
+ def initialize(attribute, record, name, options)
15
+ raise MissingOptions if options.nil?
16
+ @attribute, @record, @name, @options = attribute, record, name, options
10
17
  @record.fauxsql_attributes[name] ||= attribute
11
18
  end
12
19
 
20
+ def get_nested_record(vals)
21
+ model = vals[:type].constantize
22
+ raise MissingOptions.new(:nest, options) unless options[:nest]
23
+ raise InvalidNesting unless options[:nest].include?(model)
24
+ model.get(vals["#{model.name}_id".to_sym])
25
+ end
26
+
13
27
  def dirty!
14
- record.attribute_set(:fauxsql_attributes, record.fauxsql_attributes.dup)
15
- value = yield
16
- record.attribute_set(:fauxsql_attributes, record.fauxsql_attributes)
17
- value
28
+ Fauxsql.dirty!(record){ yield }
18
29
  end
19
30
  end
20
31
  end
@@ -0,0 +1,5 @@
1
+ class Fauxsql::Attributes < Hash
2
+ def eql?(other)
3
+ return false
4
+ end
5
+ end
@@ -1,3 +1,4 @@
1
+ require "active_support/inflector"
1
2
  module Fauxsql
2
3
  # DereferencedAttribute stores objects that quack like DataMapper::Resource
3
4
  # This is the object that Fauxsql stores in the database when a
@@ -6,12 +7,12 @@ module Fauxsql
6
7
  class DereferencedAttribute
7
8
  @@identity_map = {}
8
9
  def initialize(attribute)
9
- @klass = attribute.class
10
+ @klass = attribute.class.to_s
10
11
  @lookup_key = attribute.key
11
12
  end
12
13
 
13
14
  def resolve
14
- @klass.get(*@lookup_key)
15
+ ActiveSupport::Inflector.constantize(@klass.to_s).get(*@lookup_key)
15
16
  end
16
17
 
17
18
  def dump
@@ -20,7 +21,8 @@ module Fauxsql
20
21
  alias hash dump
21
22
 
22
23
  def self.get(attribute)
23
- @@identity_map[attribute] ||= new(attribute)
24
+ dereferenced = new(attribute)
25
+ @@identity_map[dereferenced.hash] ||= dereferenced
24
26
  end
25
27
 
26
28
  def self.load(dump)
data/lib/fauxsql/dsl.rb CHANGED
@@ -1,5 +1,7 @@
1
+ require "active_support/inflector"
1
2
  module Fauxsql
2
3
  module DSL
4
+ class InvalidNesting < StandardError; end
3
5
  # DSL method to define a named Fauxsql attribute
4
6
  #
5
7
  # calling with 'power' is like writing:
@@ -10,8 +12,9 @@ module Fauxsql
10
12
  # def power=(value)
11
13
  # set_fauxsql_attribute(:power, value)
12
14
  # end
13
- def attribute(attribute_name)
14
- class_eval <<EORUBY
15
+ def attribute(attribute_name, options={})
16
+ fauxsql_options[attribute_name] = normalize_options!(options)
17
+ class_eval <<EORUBY, __FILE__, __LINE__
15
18
  def #{attribute_name}
16
19
  get_fauxsql_attribute(:#{attribute_name})
17
20
  end
@@ -20,6 +23,15 @@ module Fauxsql
20
23
  set_fauxsql_attribute(:#{attribute_name}, value)
21
24
  end
22
25
  EORUBY
26
+
27
+ if options[:nest]
28
+ class_eval <<EORUBY, __FILE__, __LINE__
29
+ def #{attribute_name}_attributes=(vals)
30
+ vals = Fauxsql::DSL.normalize_nested_vals!(vals)
31
+ #{attribute_name} = #{attribute_name}.get_nested_record(vals)
32
+ end
33
+ EORUBY
34
+ end
23
35
  end
24
36
 
25
37
  # DSL method to define a named Fauxsql list
@@ -28,12 +40,26 @@ EORUBY
28
40
  # def squad_members
29
41
  # get_fauxsql_list(:squad_members)
30
42
  # end
31
- def list(attribute_name)
32
- class_eval <<EORUBY
43
+ def list(attribute_name, options={})
44
+ fauxsql_options[attribute_name] = normalize_options!(options)
45
+ class_eval <<EORUBY, __FILE__, __LINE__
33
46
  def #{attribute_name}
34
47
  get_fauxsql_list(:#{attribute_name})
35
48
  end
36
49
  EORUBY
50
+
51
+ if options[:nest]
52
+ class_eval <<EORUBY, __FILE__, __LINE__
53
+ def #{attribute_name}=(attrs)
54
+ #{attribute_name}.clear
55
+ attrs.each do |index, vals|
56
+ vals = Fauxsql::DSL.normalize_nested_vals!(vals)
57
+ record = #{attribute_name}.get_nested_record(vals)
58
+ #{attribute_name} << record if record unless vals[:_delete]
59
+ end
60
+ end
61
+ EORUBY
62
+ end
37
63
  end
38
64
 
39
65
  # DSL method to define a named Fauxsql map
@@ -42,12 +68,53 @@ EORUBY
42
68
  # def mitigates
43
69
  # get_fauxsql_map(:mitigates)
44
70
  # end
45
- def map(attribute_name)
46
- class_eval <<EORUBY
71
+ def map(attribute_name, options={})
72
+ fauxsql_options[attribute_name] = normalize_options!(options)
73
+ class_eval <<EORUBY, __FILE__, __LINE__
47
74
  def #{attribute_name}
48
75
  get_fauxsql_map(:#{attribute_name})
49
76
  end
50
77
  EORUBY
78
+
79
+ if options[:nest]
80
+ class_eval <<EORUBY, __FILE__, __LINE__
81
+ def #{attribute_name}=(attrs)
82
+ deletes = []
83
+ attrs.each do |index, vals|
84
+ vals = Fauxsql::DSL.normalize_nested_vals!(vals)
85
+ key = #{attribute_name}.get_nested_record(vals)
86
+ #{attribute_name}[key] = vals[:value]
87
+ deletes << key if vals[:_delete]
88
+ end
89
+ deletes.each{ |key| #{attribute_name}.delete(key) }
90
+ end
91
+ EORUBY
92
+ end
93
+ end
94
+
95
+ # DSL method to define a named Fauxsql manymany relationship
96
+ #
97
+ # calling with 'friends' is like writing:
98
+ # def friends
99
+ # get_fauxsql_manymany(:friends, Other, :through => :friends)
100
+ # end
101
+ def manymany(attribute_name, classes, options)
102
+ define_method attribute_name do
103
+ get_fauxsql_manymany(attribute_name, classes, options)
104
+ end
105
+ end
106
+
107
+ private
108
+
109
+ def normalize_options!(options)
110
+ options[:nest] = [options[:nest]] if options[:nest] unless options[:nest].is_a?(Array)
111
+ options.freeze
112
+ end
113
+
114
+ def self.normalize_nested_vals!(vals)
115
+ vals[:_delete] = true if vals[:_delete] == "1" # Rails forms return "1" for nested attributes deletion.
116
+ vals[:_delete] = false unless vals[:_delete] == true
117
+ vals.freeze
51
118
  end
52
119
  end
53
120
  end
@@ -1,12 +1,15 @@
1
- require "active_support/dependencies"
2
1
  require "active_support/core_ext/module/delegation"
3
2
  module Fauxsql
4
3
  class ListWrapper < AttributeWrapper
5
4
  alias list attribute
6
- delegate :[], :==, :<<, :first, :last, :equals, :map_resolved, :to => :list
5
+ delegate :[], :==, :first, :last, :each, :each_with_index, :map, :all, :equals, :to => :list
7
6
 
8
7
  def <<(item)
9
8
  dirty! { list << item }
10
9
  end
10
+
11
+ def clear
12
+ dirty! { list.clear }
13
+ end
11
14
  end
12
15
  end
@@ -0,0 +1,43 @@
1
+ require "active_support/core_ext/module/delegation"
2
+ require 'active_support/core_ext/array/extract_options'
3
+ module Fauxsql
4
+ class ManymanyWrapper < AttributeWrapper
5
+ class ThroughOptionMissing < StandardError; end
6
+ class InvalidManymanyAssociationClass < StandardError; end
7
+
8
+ alias list attribute
9
+ delegate :-, :[], :==, :first, :last, :each, :each_with_index, :map, :all, :equals, :to => :list
10
+
11
+ def initialize(attribute, record, name, *classes)
12
+ super(attribute, record, name, {})
13
+ options = classes.extract_options!
14
+ raise ThroughOptionMissing unless options[:through]
15
+ @classes, @through = classes, options[:through]
16
+ end
17
+
18
+ def <<(other)
19
+ raise InvalidManymanyAssociationClass unless @classes.include?(other.class)
20
+ other.send(@through).clean_push(record)
21
+ clean_push(other)
22
+ end
23
+
24
+ def delete(*others)
25
+ raise InvalidManymanyAssociationClass if (@classes - others.map{|other| other.class }).any?
26
+ clean_subtract(others)
27
+ others.each{ |other| other.send(@through).clean_subtract([record]) }
28
+ # # DataMapper.transaction do # TODO the transaction?
29
+ others.each{|other| other.save}
30
+ record.save
31
+ # end
32
+ end
33
+
34
+ protected
35
+ def clean_push(other)
36
+ dirty! { list << other }
37
+ end
38
+
39
+ def clean_subtract(others)
40
+ dirty! { @attribute = list - others }
41
+ end
42
+ end
43
+ end
@@ -1,12 +1,20 @@
1
- require "active_support/dependencies"
2
1
  require "active_support/core_ext/module/delegation"
3
2
  module Fauxsql
4
3
  class MapWrapper < AttributeWrapper
5
4
  alias map attribute
6
- delegate :[], :each, :keys, :resolve_key, :resolve_value, :to => :map
5
+ delegate :[], :each, :each_with_index, :keys, :resolve_key, :resolve_value, :to => :map
7
6
 
8
7
  def []=(key, value)
8
+ value = value.send(options[:value_type]) if options[:value_type]
9
9
  dirty! { map[key] = value }
10
10
  end
11
+
12
+ def [](key)
13
+ options[:value_type] ? map[key].send(options[:value_type]) : map[key]
14
+ end
15
+
16
+ def delete(key)
17
+ dirty! { map.delete(key) }
18
+ end
11
19
  end
12
20
  end
@@ -0,0 +1,5 @@
1
+ class Fauxsql::Options < Hash
2
+ def [](key)
3
+ super(key) || {}
4
+ end
5
+ end
data/lib/fauxsql.rb CHANGED
@@ -6,48 +6,69 @@ require 'pathname'
6
6
  # Internal Libs
7
7
  root = Pathname.new(__FILE__).dirname.expand_path
8
8
  require root+'fauxsql/dereferenced_attribute'
9
+ require root+'fauxsql/attributes'
10
+ require root+'fauxsql/options'
9
11
  require root+'fauxsql/attribute_list'
10
12
  require root+'fauxsql/attribute_map'
13
+ require root+'fauxsql/attribute_manymany'
11
14
  require root+'fauxsql/attribute_wrapper'
12
15
  require root+'fauxsql/map_wrapper'
13
16
  require root+'fauxsql/list_wrapper'
17
+ require root+'fauxsql/manymany_wrapper'
14
18
  require root+'fauxsql/dsl'
15
19
  module Fauxsql
16
20
  extend ActiveSupport::Concern
17
21
 
18
22
  included do
19
- property :fauxsql_attributes, Object, :default => {}
23
+ # Property is lazy. Benchmark for lazy loading shows
24
+ # performance is up to 5x slower when accessing fauxsql attributes.
25
+ property :fauxsql_attributes, Object,
26
+ :default => lambda{|*| Fauxsql::Attributes.new },
27
+ :lazy => false
20
28
  extend Fauxsql::DSL
29
+ cattr_accessor :fauxsql_options
30
+ self.fauxsql_options = Fauxsql::Options.new
21
31
  end
22
32
 
23
33
  # Getter method for attributes defined as:
24
34
  # attribute :attribute_name
25
35
  def get_fauxsql_attribute(attribute_name)
26
36
  attribute = fauxsql_attributes[attribute_name]
27
- Fauxsql.resolve_fauxsql_attribute(attribute)
37
+ value = Fauxsql.resolve_fauxsql_attribute(attribute)
38
+
39
+ options = fauxsql_options[attribute_name]
40
+ options and options[:type] ? value.send(options[:type]) : value
28
41
  end
29
42
 
30
43
  # Setter method for attributes defined as:
31
44
  # attribute :attribute_name
32
45
  def set_fauxsql_attribute(attribute_name, value)
46
+ options = fauxsql_options[attribute_name]
47
+ value = value.send(options[:type]) if options and options[:type]
48
+
33
49
  attribute = Fauxsql.dereference_fauxsql_attribute(value)
34
- fauxsql_attributes[attribute_name] = attribute
50
+ Fauxsql.dirty!(self){ fauxsql_attributes[attribute_name] = attribute }
35
51
  end
36
52
 
37
53
  # Gets a reference to an AttributeList object. AttributeList quacks like
38
54
  # a Ruby Array. Except it uses Fauxsql's dereference and resolve strategy to
39
55
  # store members.
40
- def get_fauxsql_list(list_name)
41
- list = fauxsql_attributes[list_name] || AttributeList.new
42
- ListWrapper.new(list, self, list_name)
56
+ def get_fauxsql_list(attribute_name)
57
+ list = fauxsql_attributes[attribute_name] || AttributeList.new
58
+ ListWrapper.new(list, self, attribute_name, fauxsql_options[attribute_name])
43
59
  end
44
60
 
45
61
  # Gets a reference to an AttributeMap object. AttributeMap quacks like
46
62
  # a Ruby Hash. Except it uses Fauxsql's dereference and resolve strategy to
47
63
  # store keys and values.
48
- def get_fauxsql_map(map_name)
49
- map = fauxsql_attributes[map_name] || AttributeMap.new
50
- MapWrapper.new(map, self, map_name)
64
+ def get_fauxsql_map(attribute_name)
65
+ map = fauxsql_attributes[attribute_name] || AttributeMap.new
66
+ MapWrapper.new(map, self, attribute_name, fauxsql_options[attribute_name])
67
+ end
68
+
69
+ def get_fauxsql_manymany(attribute_name, classes, options)
70
+ manymany = fauxsql_attributes[attribute_name] || AttributeManymany.new
71
+ ManymanyWrapper.new(manymany, self, attribute_name, classes, options)
51
72
  end
52
73
 
53
74
  # When setting values, all attributes pass through this method.
@@ -71,4 +92,12 @@ module Fauxsql
71
92
  attribute
72
93
  end
73
94
  end
95
+
96
+ def self.dirty!(record)
97
+ record.attribute_set(:fauxsql_attributes, record.fauxsql_attributes.dup)
98
+ value = yield
99
+ record.attribute_set(:fauxsql_attributes, record.fauxsql_attributes)
100
+ value
101
+ end
102
+
74
103
  end
data/test/helper.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'test/unit'
3
3
  require 'shoulda'
4
-
4
+ require 'dm-core'
5
5
  require 'datamapper'
6
6
  DataMapper.setup(:default, "sqlite3://:memory:")
7
7
 
@@ -10,8 +10,15 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
10
10
  require 'fauxsql'
11
11
 
12
12
  class Test::Unit::TestCase
13
- def reload
14
- @faux.save
15
- @faux.reload
13
+ def checkpoint!
14
+ if @faux
15
+ @faux.save
16
+ @faux.reload
17
+ end
18
+
19
+ if @other
20
+ @other.save
21
+ @other.reload
22
+ end
16
23
  end
17
24
  end
data/test/test_fauxsql.rb CHANGED
@@ -18,9 +18,13 @@ class FauxObject
18
18
  property :id, Serial
19
19
  property :type, Discriminator
20
20
  attribute :name
21
- attribute :record
22
- list :things
23
- map :dictionary
21
+ attribute :record, :nest => FauxObject
22
+ attribute :number, :type => :to_i
23
+ list :things, :nest => FauxObject
24
+ map :dictionary, :nest => FauxObject
25
+ map :numbers, :value_type => :to_i
26
+
27
+ manymany :others, FauxObject, :through => :others#, :nest => true TODO implement nesting on manymany
24
28
  end
25
29
 
26
30
  class OtherFauxObject < FauxObject; end
@@ -47,21 +51,29 @@ class TestFauxsql < Test::Unit::TestCase
47
51
 
48
52
  should "persist attributes" do
49
53
  @faux.name = "MyName"
50
- reload
54
+ checkpoint!
51
55
  assert_equal "MyName", @faux.name
52
56
  end
53
57
 
58
+ should "update attributes" do
59
+ @faux.name = "AName"
60
+ checkpoint!
61
+ @faux.name = "OtherName"
62
+ checkpoint!
63
+ assert_equal "OtherName", @faux.name
64
+ end
65
+
54
66
  should "persist lists" do
55
67
  @faux.things << :hello
56
68
  @faux.things << :goodbye
57
- reload
69
+ checkpoint!
58
70
  assert @faux.things == [:hello, :goodbye]
59
71
  end
60
72
 
61
73
  should "persist maps" do
62
74
  @faux.dictionary[:a] = 1
63
75
  @faux.dictionary[:b] = 2
64
- reload
76
+ checkpoint!
65
77
  assert_equal 1, @faux.dictionary[:a]
66
78
  assert_equal 2, @faux.dictionary[:b]
67
79
  end
@@ -69,14 +81,14 @@ class TestFauxsql < Test::Unit::TestCase
69
81
  should "dereference and resolve objects that include Fauxsql" do
70
82
  has_fauxsql = OtherFauxObject.create
71
83
  @faux.record = has_fauxsql
72
- reload
84
+ checkpoint!
73
85
  assert_equal has_fauxsql, @faux.record
74
86
  end
75
87
 
76
88
  should "dereference and resolve dm objects with simple keys" do
77
89
  simple_key = SimpleKey.create
78
90
  @faux.record = simple_key
79
- reload
91
+ checkpoint!
80
92
  assert @faux.fauxsql_attributes[:record].is_a?(Fauxsql::DereferencedAttribute)
81
93
  assert_equal simple_key, @faux.record
82
94
  end
@@ -84,7 +96,7 @@ class TestFauxsql < Test::Unit::TestCase
84
96
  should "deference and resolve dm objects with complex keys" do
85
97
  complex_key = ComplexKey.create(:string => "string", :integer => 1)
86
98
  @faux.record = complex_key
87
- reload
99
+ checkpoint!
88
100
  assert @faux.fauxsql_attributes[:record].is_a?(Fauxsql::DereferencedAttribute)
89
101
  assert_equal complex_key, @faux.record
90
102
  end
@@ -94,24 +106,36 @@ class TestFauxsql < Test::Unit::TestCase
94
106
  @faux.things << :hello
95
107
  @faux.things << simple
96
108
  @faux.things << :goodbye
97
- reload
98
- assert_equal [:hello, simple, :goodbye], @faux.things.map_resolved
109
+ checkpoint!
110
+ assert_equal [:hello, simple, :goodbye], @faux.things.all
99
111
  end
100
-
112
+
101
113
  should "derefencenc and resolve fauxsql objects in lists" do
102
114
  has_fauxsql = OtherFauxObject.create
103
115
  @faux.things << :hello
104
116
  @faux.things << has_fauxsql
105
117
  @faux.things << :goodbye
106
- reload
107
- assert_equal [:hello, has_fauxsql, :goodbye], @faux.things.map_resolved
118
+ checkpoint!
119
+ assert_equal [:hello, has_fauxsql, :goodbye], @faux.things.all
120
+ end
121
+
122
+ should "derefencenc and resolve fauxsql objects in lists when calling each/each_with_index" do
123
+ has_fauxsql = OtherFauxObject.create
124
+ @faux.things << has_fauxsql
125
+ checkpoint!
126
+ @faux.things.each_with_index do |thing, index|
127
+ assert_equal has_fauxsql, thing
128
+ end
129
+ @faux.things.each do |thing|
130
+ assert_equal has_fauxsql, thing
131
+ end
108
132
  end
109
133
 
110
134
  should "derference and resolve dm objects with fauxsql in maps" do
111
135
  has_fauxsql1 = OtherFauxObject.create
112
136
  has_fauxsql2 = OtherFauxObject.create
113
137
  @faux.dictionary[has_fauxsql1] = has_fauxsql2
114
- reload
138
+ checkpoint!
115
139
  assert_equal has_fauxsql2, @faux.dictionary[has_fauxsql1]
116
140
  end
117
141
 
@@ -120,7 +144,7 @@ class TestFauxsql < Test::Unit::TestCase
120
144
  simple2 = SimpleKey.create
121
145
  @faux.dictionary[simple1] = simple2
122
146
  assert_equal SimpleKey, @faux.dictionary.keys.first.class
123
- reload
147
+ checkpoint!
124
148
  assert_equal simple2, @faux.dictionary[simple1]
125
149
  end
126
150
 
@@ -128,7 +152,7 @@ class TestFauxsql < Test::Unit::TestCase
128
152
  simple1 = SimpleKey.create
129
153
  simple2 = SimpleKey.create
130
154
  @faux.dictionary[simple1] = simple2
131
- reload
155
+ checkpoint!
132
156
  @faux.dictionary.each do |key, value|
133
157
  assert_equal simple1, key
134
158
  assert_equal simple2, value
@@ -138,18 +162,188 @@ class TestFauxsql < Test::Unit::TestCase
138
162
  should "not choke on normal values in hash when calling #each" do
139
163
  simple1 = SimpleKey.create
140
164
  @faux.dictionary[simple1] = 33
141
- reload
165
+ checkpoint!
142
166
  @faux.dictionary.each{|key, value| }
143
167
  assert true, "choked on normal values in #each"
144
168
  end
145
-
169
+
146
170
  should "persist changes to maps" do
147
171
  simple1 = SimpleKey.create
148
172
  @faux.dictionary[simple1] = 33
149
- reload
173
+ checkpoint!
150
174
  @faux.dictionary[simple1] = 50
151
- reload
175
+ checkpoint!
152
176
  assert_equal 50, @faux.dictionary[simple1]
153
177
  end
178
+
179
+ should "persist changes to lists" do
180
+ has_fauxsql = OtherFauxObject.create
181
+ @faux.things << :hello
182
+ @faux.things << has_fauxsql
183
+ @faux.things << :goodbye
184
+ checkpoint!
185
+ @faux.things.clear
186
+ checkpoint!
187
+ assert_equal [], @faux.things.all
188
+ end
189
+
190
+ should "delete items from maps" do
191
+ simple1 = SimpleKey.create
192
+ @faux.dictionary[simple1] = 33
193
+ checkpoint!
194
+ @faux.dictionary.delete(simple1)
195
+ checkpoint!
196
+ assert_equal nil, @faux.dictionary[simple1]
197
+ end
198
+
199
+ should "obey typecasting directives for attributes" do
200
+ @faux.number = "33"
201
+ checkpoint!
202
+ assert_equal 33, @faux.number
203
+ end
204
+
205
+ should "obey typecasting directives for map values" do
206
+ @faux.numbers[:a] = "400"
207
+ checkpoint!
208
+ assert_equal 400, @faux.numbers[:a]
209
+ end
210
+
211
+ should "obey typecasting directives for map keys" do
212
+ assert false
213
+ end
214
+
215
+ should "obey typecasting directives for list items" do
216
+ assert false
217
+ end
218
+
219
+ context "with :nested => *" do
220
+ context "on a map" do
221
+ should "accept nested attributes" do
222
+ other = FauxObject.create
223
+ @faux.dictionary = { "0" => {
224
+ :type => other.class.name,
225
+ "#{other.class.name}_id".intern => other.id,
226
+ :value => "Nested"
227
+ }}
228
+ checkpoint!
229
+ assert_equal "Nested", @faux.dictionary[other]
230
+ end
231
+
232
+ should "delete nested attributes" do
233
+ other = FauxObject.create
234
+ @faux.dictionary = { "0" => {
235
+ :type => other.class.name,
236
+ "#{other.class.name}_id".intern => other.id,
237
+ :value => "Nested"
238
+ }}
239
+ checkpoint!
240
+ @faux.dictionary = { "0" => {
241
+ :type => other.class.name,
242
+ "#{other.class.name}_id".intern => other.id,
243
+ :_delete => true
244
+ }}
245
+ checkpoint!
246
+ assert_equal [], @faux.dictionary.keys
247
+ end
248
+ end
249
+
250
+ context "on a list" do
251
+ should "accept nested attributes" do
252
+ other = FauxObject.create
253
+ @faux.things = { "0" => {
254
+ :type => other.class.name,
255
+ "#{other.class.name}_id".intern => other.id
256
+ }}
257
+ checkpoint!
258
+ assert_equal [other], @faux.things.all
259
+ end
260
+
261
+ should "delete nested attributes" do
262
+ other = FauxObject.create
263
+ @faux.things = { "0" => {
264
+ :type => other.class.name,
265
+ "#{other.class.name}_id".intern => other.id
266
+ }}
267
+ checkpoint!
268
+ @faux.things = { "0" => {
269
+ :type => other.class.name,
270
+ "#{other.class.name}_id".intern => other.id,
271
+ :_delete => true
272
+ }}
273
+ checkpoint!
274
+ assert_equal [], @faux.things.all
275
+ end
276
+ end
277
+
278
+ context "on an attribute" do
279
+ should "accept nested attribute" do
280
+ assert false
281
+ # other = FauxObject.create
282
+ # @faux.record = {
283
+ # :type => other.class.name,
284
+ # "#{other.class.name}_id".intern => other.id
285
+ # }
286
+ # checkpoint!
287
+ # assert_equal other, @faux.record
288
+ end
289
+
290
+ should "delete nested attribute" do
291
+ assert false
292
+ # other = FauxObject.create
293
+ # @faux.record = {
294
+ # :type => other.class.name,
295
+ # "#{other.class.name}_id".intern => other.id
296
+ # }
297
+ # checkpoint!
298
+ # other = FauxObject.create
299
+ # @faux.record = {
300
+ # :type => other.class.name,
301
+ # "#{other.class.name}_id".intern => other.id,
302
+ # :_delete => true
303
+ # }
304
+ # checkpoint!
305
+ # assert_equal nil, @faux.record
306
+ end
307
+ end
308
+ end
309
+
310
+ context "with a manymany relationship" do
311
+ setup do
312
+ @faux = FauxObject.create!
313
+ @other = FauxObject.create!
314
+ @faux.others << @other
315
+ checkpoint!
316
+ end
317
+
318
+ should "associate manymany relationships" do
319
+ assert_equal [@faux], @other.others.all # LOL "LOST" JOKE
320
+ assert_equal [@other], @faux.others.all
321
+ end
322
+
323
+ should "delete from manymany relationships" do
324
+ third = FauxObject.create
325
+ @faux.others << third
326
+ checkpoint!
327
+ @faux.others.delete(@other)
328
+ checkpoint!
329
+ third.save; third.reload
330
+ assert_equal [third], @faux.others.all
331
+ assert_equal [], @other.others.all
332
+ end
333
+
334
+ # TODO think about paranoid deletion
335
+ end
336
+
337
+ should "allow changing of hash key when key is record" do
338
+ assert false
339
+ end
340
+
341
+ should "return keys for dictionary stores" do
342
+ @faux.dictionary['a'] = 1
343
+ @faux.dictionary['b'] = 1
344
+ @faux.dictionary['c'] = 1
345
+ checkpoint!
346
+ assert_equal ['a', 'b', 'c'], @faux.dictionary.keys
347
+ end
154
348
  end
155
349
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
8
7
  - 2
9
- version: 0.1.2
8
+ - 0
9
+ version: 0.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Collin Miller
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-04-20 00:00:00 -04:00
17
+ date: 2010-05-06 00:00:00 -04:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -87,12 +87,16 @@ files:
87
87
  - fauxsql.gemspec
88
88
  - lib/fauxsql.rb
89
89
  - lib/fauxsql/attribute_list.rb
90
+ - lib/fauxsql/attribute_manymany.rb
90
91
  - lib/fauxsql/attribute_map.rb
91
92
  - lib/fauxsql/attribute_wrapper.rb
93
+ - lib/fauxsql/attributes.rb
92
94
  - lib/fauxsql/dereferenced_attribute.rb
93
95
  - lib/fauxsql/dsl.rb
94
96
  - lib/fauxsql/list_wrapper.rb
97
+ - lib/fauxsql/manymany_wrapper.rb
95
98
  - lib/fauxsql/map_wrapper.rb
99
+ - lib/fauxsql/options.rb
96
100
  - test/helper.rb
97
101
  - test/test_fauxsql.rb
98
102
  has_rdoc: true