mack-data_mapper 0.8.1 → 0.8.2
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/lib/gems/addressable-2.0.0/lib/addressable/idna.rb +4867 -0
- data/lib/gems/addressable-2.0.0/lib/addressable/uri.rb +2469 -0
- data/lib/gems/addressable-2.0.0/lib/addressable/version.rb +35 -0
- data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/adapters/data_objects_adapter.rb +85 -0
- data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/aggregate_functions.rb +201 -0
- data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/collection.rb +11 -0
- data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/model.rb +11 -0
- data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/repository.rb +7 -0
- data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/support/symbol.rb +21 -0
- data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates/version.rb +7 -0
- data/lib/gems/dm-aggregates-0.9.7/lib/dm-aggregates.rb +15 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/abstract_adapter.rb +209 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/data_objects_adapter.rb +709 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/in_memory_adapter.rb +87 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/mysql_adapter.rb +136 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/postgres_adapter.rb +188 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters/sqlite3_adapter.rb +105 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/adapters.rb +22 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/many_to_many.rb +147 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/many_to_one.rb +107 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/one_to_many.rb +318 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/one_to_one.rb +61 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/relationship.rb +223 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/associations/relationship_chain.rb +81 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/associations.rb +200 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/auto_migrations.rb +105 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/collection.rb +642 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/dependency_queue.rb +32 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/hook.rb +11 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/identity_map.rb +42 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/is.rb +16 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/logger.rb +232 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/migrations/destructive_migrations.rb +17 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/migrator.rb +29 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/model.rb +488 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/naming_conventions.rb +84 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/property.rb +663 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/property_set.rb +169 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/query.rb +628 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/repository.rb +159 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/resource.rb +637 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/scope.rb +58 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/support/array.rb +13 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/support/assertions.rb +8 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/support/errors.rb +23 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/support/kernel.rb +11 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/support/symbol.rb +41 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/support.rb +7 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/transaction.rb +267 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/type.rb +160 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/type_map.rb +80 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/types/boolean.rb +7 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/types/discriminator.rb +34 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/types/object.rb +24 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/types/paranoid_boolean.rb +34 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/types/paranoid_datetime.rb +33 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/types/serial.rb +9 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/types/text.rb +10 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/types.rb +19 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core/version.rb +3 -0
- data/lib/gems/dm-core-0.9.7/lib/dm-core.rb +217 -0
- data/lib/gems/dm-core-0.9.7/script/all +5 -0
- data/lib/gems/dm-core-0.9.7/script/performance.rb +284 -0
- data/lib/gems/dm-core-0.9.7/script/profile.rb +87 -0
- data/lib/gems/dm-migrations-0.9.7/lib/dm-migrations/version.rb +5 -0
- data/lib/gems/dm-migrations-0.9.7/lib/dm-migrations.rb +1 -0
- data/lib/gems/dm-migrations-0.9.7/lib/migration.rb +215 -0
- data/lib/gems/dm-migrations-0.9.7/lib/migration_runner.rb +88 -0
- data/lib/gems/dm-migrations-0.9.7/lib/spec/example/migration_example_group.rb +73 -0
- data/lib/gems/dm-migrations-0.9.7/lib/spec/matchers/migration_matchers.rb +107 -0
- data/lib/gems/dm-migrations-0.9.7/lib/sql/column.rb +9 -0
- data/lib/gems/dm-migrations-0.9.7/lib/sql/mysql.rb +52 -0
- data/lib/gems/dm-migrations-0.9.7/lib/sql/postgresql.rb +78 -0
- data/lib/gems/dm-migrations-0.9.7/lib/sql/sqlite3.rb +43 -0
- data/lib/gems/dm-migrations-0.9.7/lib/sql/table.rb +19 -0
- data/lib/gems/dm-migrations-0.9.7/lib/sql/table_creator.rb +81 -0
- data/lib/gems/dm-migrations-0.9.7/lib/sql/table_modifier.rb +53 -0
- data/lib/gems/dm-migrations-0.9.7/lib/sql.rb +10 -0
- data/lib/gems/dm-observer-0.9.7/lib/dm-observer/version.rb +5 -0
- data/lib/gems/dm-observer-0.9.7/lib/dm-observer.rb +91 -0
- data/lib/gems/dm-serializer-0.9.7/lib/dm-serializer/version.rb +5 -0
- data/lib/gems/dm-serializer-0.9.7/lib/dm-serializer.rb +183 -0
- data/lib/gems/dm-timestamps-0.9.7/lib/dm-timestamps/version.rb +5 -0
- data/lib/gems/dm-timestamps-0.9.7/lib/dm-timestamps.rb +57 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/bcrypt_hash.rb +31 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/csv.rb +28 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/enum.rb +70 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/epoch_time.rb +27 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/file_path.rb +27 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/flag.rb +61 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/ip_address.rb +30 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/json.rb +40 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/regexp.rb +20 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/serial.rb +8 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/slug.rb +37 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/uri.rb +29 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/uuid.rb +64 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/version.rb +5 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types/yaml.rb +36 -0
- data/lib/gems/dm-types-0.9.7/lib/dm-types.rb +28 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/absent_field_validator.rb +60 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/acceptance_validator.rb +76 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/auto_validate.rb +153 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/block_validator.rb +60 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/confirmation_validator.rb +80 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/contextual_validators.rb +56 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/custom_validator.rb +72 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/format_validator.rb +97 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/formats/email.rb +40 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/formats/url.rb +20 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/generic_validator.rb +100 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/length_validator.rb +113 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/method_validator.rb +68 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/numeric_validator.rb +83 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/primitive_validator.rb +60 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/required_field_validator.rb +88 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/support/object.rb +5 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/uniqueness_validator.rb +64 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/validation_errors.rb +63 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/version.rb +5 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations/within_validator.rb +53 -0
- data/lib/gems/dm-validations-0.9.7/lib/dm-validations.rb +234 -0
- data/lib/gems/json_pure-1.1.3/GPL +340 -0
- data/lib/gems/json_pure-1.1.3/VERSION +1 -0
- data/lib/gems/json_pure-1.1.3/bin/edit_json.rb +10 -0
- data/lib/gems/json_pure-1.1.3/bin/prettify_json.rb +76 -0
- data/lib/gems/json_pure-1.1.3/lib/json/Array.xpm +21 -0
- data/lib/gems/json_pure-1.1.3/lib/json/FalseClass.xpm +21 -0
- data/lib/gems/json_pure-1.1.3/lib/json/Hash.xpm +21 -0
- data/lib/gems/json_pure-1.1.3/lib/json/Key.xpm +73 -0
- data/lib/gems/json_pure-1.1.3/lib/json/NilClass.xpm +21 -0
- data/lib/gems/json_pure-1.1.3/lib/json/Numeric.xpm +28 -0
- data/lib/gems/json_pure-1.1.3/lib/json/String.xpm +96 -0
- data/lib/gems/json_pure-1.1.3/lib/json/TrueClass.xpm +21 -0
- data/lib/gems/json_pure-1.1.3/lib/json/add/core.rb +135 -0
- data/lib/gems/json_pure-1.1.3/lib/json/add/rails.rb +58 -0
- data/lib/gems/json_pure-1.1.3/lib/json/common.rb +354 -0
- data/lib/gems/json_pure-1.1.3/lib/json/editor.rb +1362 -0
- data/lib/gems/json_pure-1.1.3/lib/json/ext.rb +13 -0
- data/lib/gems/json_pure-1.1.3/lib/json/json.xpm +1499 -0
- data/lib/gems/json_pure-1.1.3/lib/json/pure/generator.rb +394 -0
- data/lib/gems/json_pure-1.1.3/lib/json/pure/parser.rb +259 -0
- data/lib/gems/json_pure-1.1.3/lib/json/pure.rb +75 -0
- data/lib/gems/json_pure-1.1.3/lib/json/version.rb +9 -0
- data/lib/gems/json_pure-1.1.3/lib/json.rb +235 -0
- data/lib/gems/launchy-0.3.2/bin/launchy +12 -0
- data/lib/gems/launchy-0.3.2/lib/launchy/application.rb +163 -0
- data/lib/gems/launchy-0.3.2/lib/launchy/browser.rb +85 -0
- data/lib/gems/launchy-0.3.2/lib/launchy/command_line.rb +48 -0
- data/lib/gems/launchy-0.3.2/lib/launchy/gemspec.rb +53 -0
- data/lib/gems/launchy-0.3.2/lib/launchy/specification.rb +133 -0
- data/lib/gems/launchy-0.3.2/lib/launchy/version.rb +18 -0
- data/lib/gems/launchy-0.3.2/lib/launchy.rb +58 -0
- data/lib/gems/uuidtools-1.0.3/lib/uuidtools/version.rb +32 -0
- data/lib/gems/uuidtools-1.0.3/lib/uuidtools.rb +648 -0
- data/lib/gems.rb +13 -0
- data/lib/mack-data_mapper/migration_generator/migration_generator.rb +5 -0
- data/lib/mack-data_mapper/migration_generator/templates/db/migrations/%=@migration_name%.rb.template +1 -1
- data/lib/mack-data_mapper/model_generator/manifest.yml +3 -3
- data/lib/mack-data_mapper/model_generator/model_generator.rb +8 -1
- data/lib/mack-data_mapper/model_generator/templates/model.rb.template +1 -1
- data/lib/mack-data_mapper/model_generator/templates/rspec.rb.template +1 -1
- data/lib/mack-data_mapper/model_generator/templates/test_case.rb.template +1 -1
- data/lib/mack-data_mapper.rb +3 -2
- data/lib/mack-data_mapper_tasks.rb +7 -0
- metadata +235 -86
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
module SQL
|
|
2
|
+
class TableCreator
|
|
3
|
+
attr_accessor :table_name, :opts
|
|
4
|
+
|
|
5
|
+
def initialize(adapter, table_name, opts = {}, &block)
|
|
6
|
+
@adapter = adapter
|
|
7
|
+
@table_name = table_name.to_s
|
|
8
|
+
@opts = opts
|
|
9
|
+
|
|
10
|
+
@columns = []
|
|
11
|
+
|
|
12
|
+
self.instance_eval &block
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def quoted_table_name
|
|
16
|
+
@adapter.send(:quote_table_name, table_name)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def column(name, type, opts = {})
|
|
20
|
+
@columns << Column.new(@adapter, name, type, opts)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def to_sql
|
|
24
|
+
"CREATE TABLE #{quoted_table_name} (#{@columns.map{ |c| c.to_sql }.join(', ')})"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# A helper for using the native NOW() SQL function in a default
|
|
28
|
+
def now
|
|
29
|
+
SqlExpr.new('NOW()')
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# A helper for using the native UUID() SQL function in a default
|
|
33
|
+
def uuid
|
|
34
|
+
SqlExpr.new('UUID()')
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class SqlExpr
|
|
38
|
+
attr_accessor :sql
|
|
39
|
+
def initialize(sql)
|
|
40
|
+
@sql = sql
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def to_s
|
|
44
|
+
@sql.to_s
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
class Column
|
|
49
|
+
attr_accessor :name, :type
|
|
50
|
+
|
|
51
|
+
def initialize(adapter, name, type, opts = {})
|
|
52
|
+
@adapter = adapter
|
|
53
|
+
@name = name.to_s
|
|
54
|
+
@opts = opts
|
|
55
|
+
@type = build_type(type)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def build_type(type_class)
|
|
59
|
+
schema = {:name => @name, :quote_column_name => quoted_name}.merge(@opts)
|
|
60
|
+
schema[:serial?] ||= schema[:serial]
|
|
61
|
+
schema[:nullable?] ||= schema[:nullable] || !schema[:not_null]
|
|
62
|
+
if type_class.is_a?(String)
|
|
63
|
+
schema[:primitive] = type_class
|
|
64
|
+
else
|
|
65
|
+
schema = @adapter.class.type_map[type_class].merge(schema)
|
|
66
|
+
end
|
|
67
|
+
@adapter.property_schema_statement(schema)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def to_sql
|
|
71
|
+
type
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def quoted_name
|
|
75
|
+
@adapter.send(:quote_column_name, name)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module SQL
|
|
2
|
+
class TableModifier
|
|
3
|
+
attr_accessor :table_name, :opts, :statements, :adapter
|
|
4
|
+
|
|
5
|
+
def initialize(adapter, table_name, opts = {}, &block)
|
|
6
|
+
@adapter = adapter
|
|
7
|
+
@table_name = table_name.to_s
|
|
8
|
+
@opts = (opts)
|
|
9
|
+
|
|
10
|
+
@statements = []
|
|
11
|
+
|
|
12
|
+
self.instance_eval &block
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def add_column(name, type, opts = {})
|
|
16
|
+
column = SQL::TableCreator::Column.new(@adapter, name, type, opts)
|
|
17
|
+
@statements << "ALTER TABLE #{quoted_table_name} ADD COLUMN #{column.to_sql}"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def drop_column(name)
|
|
21
|
+
# raise NotImplemented for SQLite3. Can't ALTER TABLE, need to copy table.
|
|
22
|
+
# We'd have to inspect it, and we can't, since we aren't executing any queries yet.
|
|
23
|
+
# TODO instead of building the SQL queries when executing the block, create AddColumn,
|
|
24
|
+
# AlterColumn and DropColumn objects that get #to_sql'd
|
|
25
|
+
if name.is_a?(Array)
|
|
26
|
+
name.each{ |n| drop_column(n) }
|
|
27
|
+
else
|
|
28
|
+
@statements << "ALTER TABLE #{quoted_table_name} DROP COLUMN #{quote_column_name(name)}"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
alias drop_columns drop_column
|
|
32
|
+
|
|
33
|
+
def rename_column(name, new_name, opts = {})
|
|
34
|
+
# raise NotImplemented for SQLite3
|
|
35
|
+
@statements << "ALTER TABLE #{quoted_table_name} RENAME COLUMN #{quote_column_name(name)} TO #{quote_column_name(new_name)}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def change_column(name, type, opts = {})
|
|
39
|
+
# raise NotImplemented for SQLite3
|
|
40
|
+
@statements << "ALTER TABLE #{quoted_table_name} ALTER COLUMN #{quote_column_name(name)} TYPE #{type}"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def quote_column_name(name)
|
|
44
|
+
@adapter.send(:quote_column_name, name.to_s)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def quoted_table_name
|
|
48
|
+
@adapter.send(:quote_table_name, table_name)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/sql/table_creator'
|
|
2
|
+
require File.dirname(__FILE__) + '/sql/table_modifier'
|
|
3
|
+
|
|
4
|
+
require File.dirname(__FILE__) + '/sql/sqlite3'
|
|
5
|
+
require File.dirname(__FILE__) + '/sql/mysql'
|
|
6
|
+
require File.dirname(__FILE__) + '/sql/postgresql'
|
|
7
|
+
|
|
8
|
+
module SQL
|
|
9
|
+
|
|
10
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
module DataMapper
|
|
2
|
+
# Observers allow you to add callback hooks to DataMapper::Resource objects
|
|
3
|
+
# in a separate class. This is great for separating out logic that is not
|
|
4
|
+
# really part of the model, but needs to be triggered by a model, or models.
|
|
5
|
+
module Observer
|
|
6
|
+
|
|
7
|
+
def self.included(klass)
|
|
8
|
+
klass.extend(ClassMethods)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module ClassMethods
|
|
12
|
+
|
|
13
|
+
attr_accessor :observing
|
|
14
|
+
|
|
15
|
+
def initialize
|
|
16
|
+
self.observing = []
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Assign an Array of Class names to watch.
|
|
20
|
+
# observe User, Article, Topic
|
|
21
|
+
def observe(*args)
|
|
22
|
+
# puts "#{self.to_s} observing... #{args.collect{|c| Extlib::Inflection.classify(c.to_s)}.join(', ')}"
|
|
23
|
+
self.observing = args
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def before(sym, &block)
|
|
27
|
+
self.observing.each do |klass|
|
|
28
|
+
klass.before(sym.to_sym, &block)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def after(sym, &block)
|
|
33
|
+
self.observing.each do |klass|
|
|
34
|
+
klass.after(sym.to_sym, &block)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def before_class_method(sym, &block)
|
|
39
|
+
self.observing.each do |klass|
|
|
40
|
+
klass.before_class_method(sym.to_sym, &block)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def after_class_method(sym, &block)
|
|
45
|
+
self.observing.each do |klass|
|
|
46
|
+
klass.after_class_method(sym.to_sym, &block)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end # ClassMethods
|
|
51
|
+
|
|
52
|
+
end # Observer
|
|
53
|
+
end # DataMapper
|
|
54
|
+
|
|
55
|
+
if $0 == __FILE__
|
|
56
|
+
require 'rubygems'
|
|
57
|
+
|
|
58
|
+
gem 'dm-core', '~>0.9.7'
|
|
59
|
+
require 'dm-core'
|
|
60
|
+
|
|
61
|
+
FileUtils.touch(File.join(Dir.pwd, "migration_test.db"))
|
|
62
|
+
DataMapper.setup(:default, "sqlite3://#{Dir.pwd}/migration_test.db")
|
|
63
|
+
|
|
64
|
+
class Foo
|
|
65
|
+
include DataMapper::Resource
|
|
66
|
+
|
|
67
|
+
property :id, Integer, :serial => true
|
|
68
|
+
property :bar, Text
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
Foo.auto_migrate!
|
|
72
|
+
|
|
73
|
+
class FooObserver
|
|
74
|
+
include DataMapper::Observer
|
|
75
|
+
|
|
76
|
+
observe :foo
|
|
77
|
+
|
|
78
|
+
before :save do
|
|
79
|
+
raise "Hell!" if self.bar.nil?
|
|
80
|
+
puts "hi"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
after :save do
|
|
84
|
+
puts "bye"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
Foo.new(:bar => "hello").save
|
|
90
|
+
|
|
91
|
+
end
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
require Pathname('rexml/document')
|
|
2
|
+
|
|
3
|
+
begin
|
|
4
|
+
require 'faster_csv'
|
|
5
|
+
rescue LoadError
|
|
6
|
+
nil
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
begin
|
|
10
|
+
require Pathname('json/ext')
|
|
11
|
+
rescue LoadError
|
|
12
|
+
require Pathname('json/pure')
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module DataMapper
|
|
16
|
+
module Serialize
|
|
17
|
+
|
|
18
|
+
# Serialize a Resource to JavaScript Object Notation (JSON; RFC 4627)
|
|
19
|
+
#
|
|
20
|
+
# @return <String> a JSON representation of the Resource
|
|
21
|
+
def to_json(options = {})
|
|
22
|
+
result = '{ '
|
|
23
|
+
fields = []
|
|
24
|
+
|
|
25
|
+
# FIXME: this should go into bunch of protected methods shared with other serialization methods
|
|
26
|
+
only_properties = Array(options[:only])
|
|
27
|
+
excluded_properties = Array(options[:exclude])
|
|
28
|
+
exclude_read_only = options[:without_read_only_attributes] || false
|
|
29
|
+
|
|
30
|
+
propset = self.class.properties(repository.name).reject do |p|
|
|
31
|
+
next if only_properties.include? p.name
|
|
32
|
+
excluded_properties.include?(p.name) || !(only_properties.empty? || only_properties.include?(p.name))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
fields += propset.map do |property|
|
|
36
|
+
"#{property.name.to_json}: #{send(property.getter).to_json}"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
if self.respond_to?(:serialize_properties)
|
|
40
|
+
self.serialize_properties.each do |k,v|
|
|
41
|
+
fields << "#{k.to_json}: #{v.to_json}"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
if self.class.respond_to?(:read_only_attributes) && exclude_read_only
|
|
46
|
+
self.class.read_only_attributes.each do |property|
|
|
47
|
+
fields << "#{property.to_json}: #{send(property).to_json}"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# add methods
|
|
52
|
+
(options[:methods] || []).each do |meth|
|
|
53
|
+
if self.respond_to?(meth)
|
|
54
|
+
fields << "#{meth.to_json}: #{send(meth).to_json}"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Note: if you want to include a whole other model via relation, use :methods
|
|
59
|
+
# comments.to_json(:relationships=>{:user=>{:include=>[:first_name],:methods=>[:age]}})
|
|
60
|
+
# add relationships
|
|
61
|
+
(options[:relationships] || {}).each do |rel,opts|
|
|
62
|
+
if self.respond_to?(rel)
|
|
63
|
+
fields << "#{rel.to_json}: #{send(rel).to_json(opts)}"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
result << fields.join(', ')
|
|
68
|
+
result << ' }'
|
|
69
|
+
result
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Serialize a Resource to comma-separated values (CSV).
|
|
73
|
+
#
|
|
74
|
+
# @return <String> a CSV representation of the Resource
|
|
75
|
+
def to_csv(writer = '')
|
|
76
|
+
FasterCSV.generate(writer) do |csv|
|
|
77
|
+
row = []
|
|
78
|
+
self.class.properties(repository.name).each do |property|
|
|
79
|
+
row << send(property.name).to_s
|
|
80
|
+
end
|
|
81
|
+
csv << row
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Serialize a Resource to XML
|
|
86
|
+
#
|
|
87
|
+
# @return <REXML::Document> an XML representation of this Resource
|
|
88
|
+
def to_xml(opts = {})
|
|
89
|
+
|
|
90
|
+
to_xml_document(opts).to_s
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Serialize a Resource to YAML
|
|
94
|
+
#
|
|
95
|
+
# @return <YAML> a YAML representation of this Resource
|
|
96
|
+
def to_yaml(opts = {})
|
|
97
|
+
YAML::quick_emit(object_id,opts) do |out|
|
|
98
|
+
out.map(nil,to_yaml_style) do |map|
|
|
99
|
+
self.class.properties(repository.name).each do |property|
|
|
100
|
+
value = send(property.name.to_sym)
|
|
101
|
+
map.add(property.name, value.is_a?(Class) ? value.to_s : value)
|
|
102
|
+
end
|
|
103
|
+
(instance_variable_get("@yaml_addes") || []).each do |k,v|
|
|
104
|
+
map.add(k.to_s,v)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
protected
|
|
111
|
+
|
|
112
|
+
# Return the name of this Resource - to be used as the root element name.
|
|
113
|
+
# This can be overloaded.
|
|
114
|
+
#
|
|
115
|
+
# @return <String> name of this Resource
|
|
116
|
+
def xml_element_name
|
|
117
|
+
Extlib::Inflection.underscore(self.class.name)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Return a REXML::Document representing this Resource
|
|
121
|
+
#
|
|
122
|
+
# @return <REXML::Document> an XML representation of this Resource
|
|
123
|
+
def to_xml_document(opts={}, doc=nil)
|
|
124
|
+
doc ||= REXML::Document.new
|
|
125
|
+
root = doc.add_element(xml_element_name)
|
|
126
|
+
|
|
127
|
+
#TODO old code base was converting single quote to double quote on attribs
|
|
128
|
+
|
|
129
|
+
self.class.properties(repository.name).each do |property|
|
|
130
|
+
value = send(property.name)
|
|
131
|
+
node = root.add_element(property.name.to_s)
|
|
132
|
+
unless property.type == String
|
|
133
|
+
node.attributes["type"] = property.type.to_s.downcase
|
|
134
|
+
end
|
|
135
|
+
node << REXML::Text.new(value.to_s) unless value.nil?
|
|
136
|
+
end
|
|
137
|
+
doc
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
end # module Serialize
|
|
141
|
+
|
|
142
|
+
module Resource
|
|
143
|
+
include Serialize
|
|
144
|
+
end # module Resource
|
|
145
|
+
|
|
146
|
+
class Collection
|
|
147
|
+
def to_yaml(opts = {})
|
|
148
|
+
to_a.to_yaml(opts)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def to_json(opts = {})
|
|
152
|
+
"[" << map {|e| e.to_json(opts)}.join(",") << "]"
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def to_xml(opts = {})
|
|
156
|
+
to_xml_document(opts).to_s
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def to_csv
|
|
160
|
+
result = ""
|
|
161
|
+
each do |item|
|
|
162
|
+
result << item.to_csv + "\n"
|
|
163
|
+
end
|
|
164
|
+
result
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
protected
|
|
168
|
+
def xml_element_name
|
|
169
|
+
Extlib::Inflection.tableize(self.model.to_s)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def to_xml_document(opts={})
|
|
173
|
+
doc = REXML::Document.new
|
|
174
|
+
root = doc.add_element(xml_element_name)
|
|
175
|
+
root.attributes["type"] = 'array'
|
|
176
|
+
each do |item|
|
|
177
|
+
item.send(:to_xml_document, opts, root)
|
|
178
|
+
end
|
|
179
|
+
doc
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
end # module DataMapper
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
|
|
3
|
+
gem 'dm-core', '~>0.9.7'
|
|
4
|
+
require 'dm-core'
|
|
5
|
+
|
|
6
|
+
module DataMapper
|
|
7
|
+
module Timestamp
|
|
8
|
+
TIMESTAMP_PROPERTIES = {
|
|
9
|
+
:updated_at => lambda { |r| r.updated_at = DateTime.now },
|
|
10
|
+
:updated_on => lambda { |r| r.updated_on = Date.today },
|
|
11
|
+
:created_at => lambda { |r| r.created_at = DateTime.now if r.new_record? && r.created_at.nil? },
|
|
12
|
+
:created_on => lambda { |r| r.created_on = Date.today if r.new_record? && r.created_on.nil?},
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
def self.included(model)
|
|
16
|
+
model.before :save, :set_timestamp_properties
|
|
17
|
+
model.send :extend, ClassMethods
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def set_timestamp_properties
|
|
23
|
+
if dirty?
|
|
24
|
+
self.class.properties.slice(*TIMESTAMP_PROPERTIES.keys).compact.each do |property|
|
|
25
|
+
TIMESTAMP_PROPERTIES[property.name][self] unless attribute_dirty?(property.name)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
module ClassMethods
|
|
31
|
+
def timestamps(*args)
|
|
32
|
+
if args.empty? then raise ArgumentError, "You need to pass at least one argument." end
|
|
33
|
+
|
|
34
|
+
args.each do |ts|
|
|
35
|
+
case ts
|
|
36
|
+
when :at
|
|
37
|
+
property :created_at, DateTime
|
|
38
|
+
property :updated_at, DateTime
|
|
39
|
+
when :on
|
|
40
|
+
property :created_on, Date
|
|
41
|
+
property :updated_on, Date
|
|
42
|
+
else
|
|
43
|
+
unless TIMESTAMP_PROPERTIES.keys.include?(ts)
|
|
44
|
+
raise InvalidTimestampName, "Invalid timestamp property '#{ts}'."
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
property ts, DateTime
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class InvalidTimestampName < RuntimeError; end
|
|
54
|
+
end # module Timestamp
|
|
55
|
+
|
|
56
|
+
Resource::append_inclusions Timestamp
|
|
57
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
|
|
2
|
+
require 'bcrypt'
|
|
3
|
+
|
|
4
|
+
module DataMapper
|
|
5
|
+
module Types
|
|
6
|
+
class BCryptHash < DataMapper::Type
|
|
7
|
+
primitive String
|
|
8
|
+
size 60
|
|
9
|
+
|
|
10
|
+
def self.load(value, property)
|
|
11
|
+
if value.nil?
|
|
12
|
+
nil
|
|
13
|
+
elsif value.is_a?(String)
|
|
14
|
+
BCrypt::Password.new(value)
|
|
15
|
+
else
|
|
16
|
+
raise ArgumentError.new("+value+ must be nil or a String")
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.dump(value, property)
|
|
21
|
+
if value.nil?
|
|
22
|
+
nil
|
|
23
|
+
elsif value.is_a?(String)
|
|
24
|
+
BCrypt::Password.create(value, :cost => BCrypt::Engine::DEFAULT_COST)
|
|
25
|
+
else
|
|
26
|
+
raise ArgumentError.new("+value+ must be nil or a String")
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end # class BCryptHash
|
|
30
|
+
end # module Types
|
|
31
|
+
end # module DataMapper
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module DataMapper
|
|
2
|
+
module Types
|
|
3
|
+
class Csv < DataMapper::Type
|
|
4
|
+
primitive String
|
|
5
|
+
size 65535
|
|
6
|
+
lazy true
|
|
7
|
+
|
|
8
|
+
def self.load(value, property)
|
|
9
|
+
case value
|
|
10
|
+
when String then FasterCSV.parse(value)
|
|
11
|
+
when Array then value
|
|
12
|
+
else nil
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.dump(value, property)
|
|
17
|
+
case value
|
|
18
|
+
when Array then
|
|
19
|
+
FasterCSV.generate do |csv|
|
|
20
|
+
value.each { |row| csv << row }
|
|
21
|
+
end
|
|
22
|
+
when String then value
|
|
23
|
+
else nil
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end # class Csv
|
|
27
|
+
end # module Types
|
|
28
|
+
end # module DataMapper
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module DataMapper
|
|
2
|
+
module Types
|
|
3
|
+
class Enum < DataMapper::Type(Integer)
|
|
4
|
+
def self.inherited(target)
|
|
5
|
+
target.instance_variable_set("@primitive", self.primitive)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def self.flag_map
|
|
9
|
+
@flag_map
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.flag_map=(value)
|
|
13
|
+
@flag_map = value
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.new(*flags)
|
|
17
|
+
enum = Class.new(Enum)
|
|
18
|
+
enum.flag_map = {}
|
|
19
|
+
|
|
20
|
+
flags.each_with_index do |flag, i|
|
|
21
|
+
enum.flag_map[i + 1] = flag
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
enum
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.[](*flags)
|
|
28
|
+
new(*flags)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.load(value, property)
|
|
32
|
+
self.flag_map[value]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.dump(value, property)
|
|
36
|
+
case value
|
|
37
|
+
when Array then value.collect { |v| self.dump(v, property) }
|
|
38
|
+
else self.flag_map.invert[value]
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.typecast(value, property)
|
|
43
|
+
# Attempt to typecast using the class of the first item in the map.
|
|
44
|
+
return value if value.nil?
|
|
45
|
+
case self.flag_map[1]
|
|
46
|
+
when Symbol then value.to_sym
|
|
47
|
+
when String then value.to_s
|
|
48
|
+
when Fixnum then value.to_i
|
|
49
|
+
else value
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end # class Enum
|
|
53
|
+
end # module Types
|
|
54
|
+
|
|
55
|
+
if defined?(Validate)
|
|
56
|
+
module Validate
|
|
57
|
+
module AutoValidate
|
|
58
|
+
alias :orig_auto_generate_validations :auto_generate_validations
|
|
59
|
+
def auto_generate_validations(property)
|
|
60
|
+
orig_auto_generate_validations(property)
|
|
61
|
+
return unless property.options[:auto_validation]
|
|
62
|
+
|
|
63
|
+
if property.type.ancestors.include?(Types::Enum)
|
|
64
|
+
validates_within property.name, options_with_message({:set => property.type.flag_map.values}, property, :within)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end # module DataMapper
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module DataMapper
|
|
2
|
+
module Types
|
|
3
|
+
class EpochTime < DataMapper::Type
|
|
4
|
+
primitive Integer
|
|
5
|
+
|
|
6
|
+
def self.load(value, property)
|
|
7
|
+
case value
|
|
8
|
+
when Integer
|
|
9
|
+
Time.at(value)
|
|
10
|
+
else
|
|
11
|
+
value
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.dump(value, property)
|
|
16
|
+
case value
|
|
17
|
+
when Integer
|
|
18
|
+
value
|
|
19
|
+
when Time
|
|
20
|
+
value.to_i
|
|
21
|
+
when DateTime
|
|
22
|
+
Time.parse(value.to_s).to_i
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end # class EpochTime
|
|
26
|
+
end # module Types
|
|
27
|
+
end # module DataMapper
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'pathname'
|
|
2
|
+
|
|
3
|
+
module DataMapper
|
|
4
|
+
module Types
|
|
5
|
+
class FilePath < DataMapper::Type
|
|
6
|
+
primitive String
|
|
7
|
+
|
|
8
|
+
def self.load(value, property)
|
|
9
|
+
if value.nil?
|
|
10
|
+
nil
|
|
11
|
+
else
|
|
12
|
+
Pathname.new(value)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.dump(value, property)
|
|
17
|
+
return nil if value.nil?
|
|
18
|
+
value.to_s
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.typecast(value, property)
|
|
22
|
+
# Leave alone if a Pathname is given.
|
|
23
|
+
value.kind_of?(Pathname) ? value : load(value, property)
|
|
24
|
+
end
|
|
25
|
+
end # class FilePath
|
|
26
|
+
end # module Types
|
|
27
|
+
end # module DataMapper
|