fauxsql 0.1.2 → 0.2.0

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