arunthampi-friendly 0.5.1
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/.document +2 -0
- data/.gitignore +26 -0
- data/APACHE-LICENSE +202 -0
- data/CHANGELOG.md +28 -0
- data/CONTRIBUTORS.md +7 -0
- data/LICENSE +20 -0
- data/README.md +288 -0
- data/Rakefile +68 -0
- data/TODO.md +5 -0
- data/VERSION +1 -0
- data/arunthampi-friendly.gemspec +241 -0
- data/examples/friendly.yml +7 -0
- data/friendly.gemspec +240 -0
- data/lib/friendly.rb +53 -0
- data/lib/friendly/associations.rb +7 -0
- data/lib/friendly/associations/association.rb +34 -0
- data/lib/friendly/associations/set.rb +37 -0
- data/lib/friendly/attribute.rb +98 -0
- data/lib/friendly/boolean.rb +10 -0
- data/lib/friendly/cache.rb +24 -0
- data/lib/friendly/cache/by_id.rb +33 -0
- data/lib/friendly/data_store.rb +73 -0
- data/lib/friendly/document.rb +70 -0
- data/lib/friendly/document/associations.rb +50 -0
- data/lib/friendly/document/attributes.rb +114 -0
- data/lib/friendly/document/convenience.rb +41 -0
- data/lib/friendly/document/mixin.rb +15 -0
- data/lib/friendly/document/scoping.rb +66 -0
- data/lib/friendly/document/storage.rb +63 -0
- data/lib/friendly/document_table.rb +56 -0
- data/lib/friendly/index.rb +73 -0
- data/lib/friendly/indexer.rb +50 -0
- data/lib/friendly/memcached.rb +48 -0
- data/lib/friendly/newrelic.rb +6 -0
- data/lib/friendly/query.rb +42 -0
- data/lib/friendly/scope.rb +100 -0
- data/lib/friendly/scope_proxy.rb +43 -0
- data/lib/friendly/sequel_monkey_patches.rb +34 -0
- data/lib/friendly/storage.rb +31 -0
- data/lib/friendly/storage_factory.rb +24 -0
- data/lib/friendly/storage_proxy.rb +111 -0
- data/lib/friendly/table.rb +15 -0
- data/lib/friendly/table_creator.rb +50 -0
- data/lib/friendly/time.rb +14 -0
- data/lib/friendly/translator.rb +33 -0
- data/lib/friendly/uuid.rb +148 -0
- data/lib/tasks/friendly.rake +7 -0
- data/rails/init.rb +3 -0
- data/spec/config.yml.example +7 -0
- data/spec/fakes/data_store_fake.rb +29 -0
- data/spec/fakes/database_fake.rb +12 -0
- data/spec/fakes/dataset_fake.rb +28 -0
- data/spec/fakes/document.rb +18 -0
- data/spec/fakes/serializer_fake.rb +12 -0
- data/spec/fakes/time_fake.rb +12 -0
- data/spec/integration/ad_hoc_scopes_spec.rb +42 -0
- data/spec/integration/basic_object_lifecycle_spec.rb +114 -0
- data/spec/integration/batch_insertion_spec.rb +29 -0
- data/spec/integration/convenience_api_spec.rb +25 -0
- data/spec/integration/count_spec.rb +12 -0
- data/spec/integration/default_value_spec.rb +30 -0
- data/spec/integration/dirty_tracking_spec.rb +43 -0
- data/spec/integration/find_via_cache_spec.rb +101 -0
- data/spec/integration/finder_spec.rb +71 -0
- data/spec/integration/has_many_spec.rb +18 -0
- data/spec/integration/index_spec.rb +57 -0
- data/spec/integration/named_scope_spec.rb +34 -0
- data/spec/integration/offline_indexing_spec.rb +53 -0
- data/spec/integration/pagination_spec.rb +63 -0
- data/spec/integration/scope_chaining_spec.rb +22 -0
- data/spec/integration/table_creator_spec.rb +69 -0
- data/spec/integration/write_through_cache_spec.rb +53 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +105 -0
- data/spec/unit/associations/association_spec.rb +57 -0
- data/spec/unit/associations/set_spec.rb +43 -0
- data/spec/unit/attribute_spec.rb +125 -0
- data/spec/unit/cache_by_id_spec.rb +102 -0
- data/spec/unit/cache_spec.rb +21 -0
- data/spec/unit/data_store_spec.rb +201 -0
- data/spec/unit/document/attributes_spec.rb +130 -0
- data/spec/unit/document_spec.rb +318 -0
- data/spec/unit/document_table_spec.rb +126 -0
- data/spec/unit/friendly_spec.rb +25 -0
- data/spec/unit/index_spec.rb +196 -0
- data/spec/unit/memcached_spec.rb +114 -0
- data/spec/unit/query_spec.rb +104 -0
- data/spec/unit/scope_proxy_spec.rb +44 -0
- data/spec/unit/scope_spec.rb +113 -0
- data/spec/unit/storage_factory_spec.rb +59 -0
- data/spec/unit/storage_proxy_spec.rb +244 -0
- data/spec/unit/translator_spec.rb +91 -0
- data/website/index.html +210 -0
- data/website/scripts/clipboard.swf +0 -0
- data/website/scripts/shBrushAS3.js +61 -0
- data/website/scripts/shBrushBash.js +66 -0
- data/website/scripts/shBrushCSharp.js +67 -0
- data/website/scripts/shBrushColdFusion.js +102 -0
- data/website/scripts/shBrushCpp.js +99 -0
- data/website/scripts/shBrushCss.js +93 -0
- data/website/scripts/shBrushDelphi.js +57 -0
- data/website/scripts/shBrushDiff.js +43 -0
- data/website/scripts/shBrushErlang.js +54 -0
- data/website/scripts/shBrushGroovy.js +69 -0
- data/website/scripts/shBrushJScript.js +52 -0
- data/website/scripts/shBrushJava.js +59 -0
- data/website/scripts/shBrushJavaFX.js +60 -0
- data/website/scripts/shBrushPerl.js +74 -0
- data/website/scripts/shBrushPhp.js +91 -0
- data/website/scripts/shBrushPlain.js +35 -0
- data/website/scripts/shBrushPowerShell.js +76 -0
- data/website/scripts/shBrushPython.js +66 -0
- data/website/scripts/shBrushRuby.js +57 -0
- data/website/scripts/shBrushScala.js +53 -0
- data/website/scripts/shBrushSql.js +68 -0
- data/website/scripts/shBrushVb.js +58 -0
- data/website/scripts/shBrushXml.js +71 -0
- data/website/scripts/shCore.js +30 -0
- data/website/scripts/shLegacy.js +30 -0
- data/website/styles/friendly.css +103 -0
- data/website/styles/help.png +0 -0
- data/website/styles/ie.css +35 -0
- data/website/styles/magnifier.png +0 -0
- data/website/styles/page_white_code.png +0 -0
- data/website/styles/page_white_copy.png +0 -0
- data/website/styles/print.css +29 -0
- data/website/styles/printer.png +0 -0
- data/website/styles/screen.css +257 -0
- data/website/styles/shCore.css +330 -0
- data/website/styles/shThemeDefault.css +173 -0
- data/website/styles/shThemeDjango.css +176 -0
- data/website/styles/shThemeEclipse.css +190 -0
- data/website/styles/shThemeEmacs.css +175 -0
- data/website/styles/shThemeFadeToGrey.css +177 -0
- data/website/styles/shThemeMidnight.css +175 -0
- data/website/styles/shThemeRDark.css +175 -0
- metadata +311 -0
data/lib/friendly.rb
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require 'friendly/associations'
|
|
2
|
+
require 'friendly/attribute'
|
|
3
|
+
require 'friendly/boolean'
|
|
4
|
+
require 'friendly/cache'
|
|
5
|
+
require 'friendly/cache/by_id'
|
|
6
|
+
require 'friendly/data_store'
|
|
7
|
+
require 'friendly/document'
|
|
8
|
+
require 'friendly/document_table'
|
|
9
|
+
require 'friendly/index'
|
|
10
|
+
require 'friendly/indexer'
|
|
11
|
+
require 'friendly/memcached'
|
|
12
|
+
require 'friendly/query'
|
|
13
|
+
require 'friendly/sequel_monkey_patches'
|
|
14
|
+
require 'friendly/scope'
|
|
15
|
+
require 'friendly/scope_proxy'
|
|
16
|
+
require 'friendly/storage_factory'
|
|
17
|
+
require 'friendly/storage_proxy'
|
|
18
|
+
require 'friendly/translator'
|
|
19
|
+
require 'friendly/uuid'
|
|
20
|
+
|
|
21
|
+
require 'json/ext'
|
|
22
|
+
require 'will_paginate/collection'
|
|
23
|
+
|
|
24
|
+
module Friendly
|
|
25
|
+
class << self
|
|
26
|
+
attr_accessor :datastore, :db, :cache
|
|
27
|
+
|
|
28
|
+
def configure(config)
|
|
29
|
+
self.db = Sequel.connect(config)
|
|
30
|
+
self.datastore = DataStore.new(db)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def batch
|
|
34
|
+
begin
|
|
35
|
+
datastore.start_batch
|
|
36
|
+
yield
|
|
37
|
+
datastore.flush_batch
|
|
38
|
+
ensure
|
|
39
|
+
datastore.reset_batch
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def create_tables!
|
|
44
|
+
Document.create_tables!
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
class Error < RuntimeError; end
|
|
49
|
+
class RecordNotFound < Error; end
|
|
50
|
+
class MissingIndex < Error; end
|
|
51
|
+
class NoConverterExists < Friendly::Error; end
|
|
52
|
+
class NotSupported < Friendly::Error; end
|
|
53
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Friendly
|
|
2
|
+
module Associations
|
|
3
|
+
class Association
|
|
4
|
+
attr_reader :owner_klass, :name
|
|
5
|
+
|
|
6
|
+
def initialize(owner_klass, name, options = {})
|
|
7
|
+
@owner_klass = owner_klass
|
|
8
|
+
@name = name
|
|
9
|
+
@class_name = options[:class_name]
|
|
10
|
+
@foreign_key = options[:foreign_key]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def klass
|
|
14
|
+
@klass ||= class_name.constantize
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def foreign_key
|
|
18
|
+
@foreign_key ||= [owner_klass_name, :id].join("_").to_sym
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def class_name
|
|
22
|
+
@class_name ||= name.to_s.classify
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def owner_klass_name
|
|
26
|
+
owner_klass.name.to_s.underscore.singularize
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def scope(document)
|
|
30
|
+
klass.scope(foreign_key => document.id)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Friendly
|
|
2
|
+
module Associations
|
|
3
|
+
class Set
|
|
4
|
+
attr_reader :klass, :association_klass, :associations
|
|
5
|
+
|
|
6
|
+
def initialize(klass, association_klass = Association)
|
|
7
|
+
@klass = klass
|
|
8
|
+
@association_klass = association_klass
|
|
9
|
+
@associations = {}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def add(name, options = {})
|
|
13
|
+
associations[name] = association_klass.new(klass, name, options)
|
|
14
|
+
add_association_accessor(name)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def get_scope(name, document)
|
|
18
|
+
get(name).scope(document)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def get(name)
|
|
22
|
+
associations[name]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
protected
|
|
26
|
+
def add_association_accessor(name)
|
|
27
|
+
klass.class_eval do
|
|
28
|
+
eval <<-__END__
|
|
29
|
+
def #{name}
|
|
30
|
+
self.class.association_set.get_scope(:#{name}, self)
|
|
31
|
+
end
|
|
32
|
+
__END__
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
module Friendly
|
|
2
|
+
class Attribute
|
|
3
|
+
class << self
|
|
4
|
+
def register_type(type, sql_type, &block)
|
|
5
|
+
sql_types[type.name] = sql_type
|
|
6
|
+
converters[type] = block
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def deregister_type(type)
|
|
10
|
+
sql_types.delete(type.name)
|
|
11
|
+
converters.delete(type)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def sql_type(type)
|
|
15
|
+
sql_types[type.name]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def sql_types
|
|
19
|
+
@sql_types ||= {}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def converters
|
|
23
|
+
@converters ||= {}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def custom_type?(klass)
|
|
27
|
+
!sql_type(klass).nil?
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
converters[Integer] = lambda { |s| s.to_i }
|
|
32
|
+
converters[String] = lambda { |s| s.to_s }
|
|
33
|
+
|
|
34
|
+
attr_reader :klass, :name, :type, :default_value
|
|
35
|
+
|
|
36
|
+
def initialize(klass, name, type, options = {})
|
|
37
|
+
@klass = klass
|
|
38
|
+
@name = name
|
|
39
|
+
@type = type
|
|
40
|
+
@default_value = options[:default]
|
|
41
|
+
build_accessors
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def typecast(value)
|
|
45
|
+
!type || value.is_a?(type) ? value : convert(value)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def convert(value)
|
|
49
|
+
assert_converter_exists(value)
|
|
50
|
+
converters[type].call(value)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def default
|
|
54
|
+
if !default_value.nil?
|
|
55
|
+
default_value
|
|
56
|
+
elsif type.respond_to?(:new)
|
|
57
|
+
type.new
|
|
58
|
+
else
|
|
59
|
+
nil
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def assign_default_value(document)
|
|
64
|
+
document.send(:"#{name}=", default)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
protected
|
|
68
|
+
def build_accessors
|
|
69
|
+
n = name
|
|
70
|
+
klass.class_eval do
|
|
71
|
+
attr_reader n, :"#{n}_was"
|
|
72
|
+
|
|
73
|
+
eval <<-__END__
|
|
74
|
+
def #{n}=(value)
|
|
75
|
+
will_change(:#{n})
|
|
76
|
+
@#{n} = self.class.attributes[:#{n}].typecast(value)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def #{n}_changed?
|
|
80
|
+
attribute_changed?(:#{n})
|
|
81
|
+
end
|
|
82
|
+
__END__
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def assert_converter_exists(value)
|
|
87
|
+
unless converters.has_key?(type)
|
|
88
|
+
msg = "Can't convert #{value} to #{type}.
|
|
89
|
+
Add a custom converter to Friendly::Attribute::CONVERTERS."
|
|
90
|
+
raise NoConverterExists, msg
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def converters
|
|
95
|
+
self.class.converters
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'friendly/storage'
|
|
2
|
+
|
|
3
|
+
module Friendly
|
|
4
|
+
class Cache < Storage
|
|
5
|
+
class << self
|
|
6
|
+
def cache_for(klass, fields, options)
|
|
7
|
+
unless fields == [:id]
|
|
8
|
+
raise NotSupported, "Caching is only possible by id at the moment."
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
ByID.new(klass, fields, options)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
attr_reader :klass, :fields, :cache, :version
|
|
16
|
+
|
|
17
|
+
def initialize(klass, fields, options = {}, cache = Friendly.cache)
|
|
18
|
+
@klass = klass
|
|
19
|
+
@fields = fields
|
|
20
|
+
@cache = cache
|
|
21
|
+
@version = options[:version] || 0
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Friendly
|
|
2
|
+
class Cache
|
|
3
|
+
class ByID < Cache
|
|
4
|
+
def store(document)
|
|
5
|
+
cache.set(cache_key(document.id), document)
|
|
6
|
+
end
|
|
7
|
+
alias_method :create, :store
|
|
8
|
+
alias_method :update, :store
|
|
9
|
+
|
|
10
|
+
def destroy(document)
|
|
11
|
+
cache.delete(cache_key(document.id))
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def first(query, &block)
|
|
15
|
+
cache.get(cache_key(query.conditions[:id]), &block)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def all(query, &block)
|
|
19
|
+
keys = query.conditions[:id].map { |k| cache_key(k) }
|
|
20
|
+
cache.multiget(keys, &block).values
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def satisfies?(query)
|
|
24
|
+
query.conditions.keys == [:id]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
protected
|
|
28
|
+
def cache_key(id)
|
|
29
|
+
[klass.name, version, id.to_guid].join("/")
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
module Friendly
|
|
2
|
+
class DataStore
|
|
3
|
+
attr_reader :database
|
|
4
|
+
|
|
5
|
+
def initialize(database)
|
|
6
|
+
@database = database
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def insert(persistable, attributes)
|
|
10
|
+
batch? ? batch_insert(persistable, attributes) :
|
|
11
|
+
immediate_insert(persistable, attributes)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def all(persistable, query)
|
|
15
|
+
filtered = dataset(persistable)
|
|
16
|
+
filtered = filtered.where(query.conditions) unless query.conditions.empty?
|
|
17
|
+
if query.limit || query.offset
|
|
18
|
+
filtered = filtered.limit(query.limit, query.offset)
|
|
19
|
+
end
|
|
20
|
+
filtered = filtered.order(query.order) if query.order
|
|
21
|
+
filtered.map
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def first(persistable, query)
|
|
25
|
+
dataset(persistable).first(query.conditions)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def update(persistable, id, attributes)
|
|
29
|
+
dataset(persistable).where(:id => id).update(attributes)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def delete(persistable, id)
|
|
33
|
+
dataset(persistable).where(:id => id).delete
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def count(persistable, query)
|
|
37
|
+
dataset(persistable).where(query.conditions).count
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def start_batch
|
|
41
|
+
Thread.current[:friendly_batch] = Hash.new { |h, k| h[k] = [] }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def reset_batch
|
|
45
|
+
Thread.current[:friendly_batch] = nil
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def flush_batch
|
|
49
|
+
batch = Thread.current[:friendly_batch]
|
|
50
|
+
batch.keys.each do |k|
|
|
51
|
+
database.from(k).multi_insert(batch[k], :commit_every => 1000)
|
|
52
|
+
end
|
|
53
|
+
reset_batch
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
protected
|
|
57
|
+
def dataset(persistable)
|
|
58
|
+
database.from(persistable.table_name)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def immediate_insert(persistable, attributes)
|
|
62
|
+
dataset(persistable).insert(attributes)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def batch_insert(persistable, attributes)
|
|
66
|
+
Thread.current[:friendly_batch][persistable.table_name] << attributes
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def batch?
|
|
70
|
+
Thread.current[:friendly_batch]
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
require 'active_support/inflector'
|
|
2
|
+
require 'friendly/document/associations'
|
|
3
|
+
require 'friendly/document/attributes'
|
|
4
|
+
require 'friendly/document/convenience'
|
|
5
|
+
require 'friendly/document/scoping'
|
|
6
|
+
require 'friendly/document/storage'
|
|
7
|
+
|
|
8
|
+
module Friendly
|
|
9
|
+
module Document
|
|
10
|
+
class << self
|
|
11
|
+
attr_writer :documents
|
|
12
|
+
|
|
13
|
+
def included(klass)
|
|
14
|
+
documents << klass
|
|
15
|
+
klass.class_eval do
|
|
16
|
+
extend ClassMethods
|
|
17
|
+
attribute :id, UUID
|
|
18
|
+
attribute :created_at, Time
|
|
19
|
+
attribute :updated_at, Time
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def documents
|
|
24
|
+
@documents ||= []
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def create_tables!
|
|
28
|
+
documents.each { |d| d.create_tables! }
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
module ClassMethods
|
|
33
|
+
attr_writer :table_name
|
|
34
|
+
|
|
35
|
+
def table_name
|
|
36
|
+
@table_name ||= name.pluralize.underscore
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
include Associations
|
|
41
|
+
include Convenience
|
|
42
|
+
include Scoping
|
|
43
|
+
include Storage
|
|
44
|
+
include Attributes
|
|
45
|
+
|
|
46
|
+
def table_name
|
|
47
|
+
self.class.table_name
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def new_record?
|
|
51
|
+
new_record
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def new_record
|
|
55
|
+
@new_record = true if @new_record.nil?
|
|
56
|
+
@new_record
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def new_record=(value)
|
|
60
|
+
@new_record = value
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def ==(comparison_object)
|
|
64
|
+
comparison_object.equal?(self) ||
|
|
65
|
+
(comparison_object.is_a?(self.class) &&
|
|
66
|
+
!comparison_object.new_record? &&
|
|
67
|
+
comparison_object.id == id)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|