hanami-model 0.6.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +44 -0
- data/README.md +54 -420
- data/hanami-model.gemspec +9 -6
- data/lib/hanami/entity.rb +107 -191
- data/lib/hanami/entity/schema.rb +236 -0
- data/lib/hanami/model.rb +52 -138
- data/lib/hanami/model/association.rb +37 -0
- data/lib/hanami/model/associations/belongs_to.rb +19 -0
- data/lib/hanami/model/associations/dsl.rb +29 -0
- data/lib/hanami/model/associations/has_many.rb +200 -0
- data/lib/hanami/model/configuration.rb +52 -224
- data/lib/hanami/model/configurator.rb +62 -0
- data/lib/hanami/model/entity_name.rb +35 -0
- data/lib/hanami/model/error.rb +37 -24
- data/lib/hanami/model/mapping.rb +29 -35
- data/lib/hanami/model/migration.rb +31 -0
- data/lib/hanami/model/migrator.rb +111 -88
- data/lib/hanami/model/migrator/adapter.rb +39 -16
- data/lib/hanami/model/migrator/connection.rb +23 -11
- data/lib/hanami/model/migrator/mysql_adapter.rb +38 -17
- data/lib/hanami/model/migrator/postgres_adapter.rb +20 -19
- data/lib/hanami/model/migrator/sqlite_adapter.rb +9 -8
- data/lib/hanami/model/plugins.rb +25 -0
- data/lib/hanami/model/plugins/mapping.rb +55 -0
- data/lib/hanami/model/plugins/schema.rb +55 -0
- data/lib/hanami/model/plugins/timestamps.rb +118 -0
- data/lib/hanami/model/relation_name.rb +24 -0
- data/lib/hanami/model/sql.rb +161 -0
- data/lib/hanami/model/sql/console.rb +41 -0
- data/lib/hanami/model/sql/consoles/abstract.rb +33 -0
- data/lib/hanami/model/sql/consoles/mysql.rb +63 -0
- data/lib/hanami/model/sql/consoles/postgresql.rb +68 -0
- data/lib/hanami/model/sql/consoles/sqlite.rb +46 -0
- data/lib/hanami/model/sql/entity/schema.rb +125 -0
- data/lib/hanami/model/sql/types.rb +95 -0
- data/lib/hanami/model/sql/types/schema/coercions.rb +198 -0
- data/lib/hanami/model/types.rb +99 -0
- data/lib/hanami/model/version.rb +1 -1
- data/lib/hanami/repository.rb +287 -723
- metadata +77 -40
- data/EXAMPLE.md +0 -213
- data/lib/hanami/entity/dirty_tracking.rb +0 -74
- data/lib/hanami/model/adapters/abstract.rb +0 -281
- data/lib/hanami/model/adapters/file_system_adapter.rb +0 -288
- data/lib/hanami/model/adapters/implementation.rb +0 -111
- data/lib/hanami/model/adapters/memory/collection.rb +0 -132
- data/lib/hanami/model/adapters/memory/command.rb +0 -113
- data/lib/hanami/model/adapters/memory/query.rb +0 -653
- data/lib/hanami/model/adapters/memory_adapter.rb +0 -179
- data/lib/hanami/model/adapters/null_adapter.rb +0 -24
- data/lib/hanami/model/adapters/sql/collection.rb +0 -287
- data/lib/hanami/model/adapters/sql/command.rb +0 -88
- data/lib/hanami/model/adapters/sql/console.rb +0 -33
- data/lib/hanami/model/adapters/sql/consoles/mysql.rb +0 -49
- data/lib/hanami/model/adapters/sql/consoles/postgresql.rb +0 -48
- data/lib/hanami/model/adapters/sql/consoles/sqlite.rb +0 -26
- data/lib/hanami/model/adapters/sql/query.rb +0 -788
- data/lib/hanami/model/adapters/sql_adapter.rb +0 -296
- data/lib/hanami/model/coercer.rb +0 -74
- data/lib/hanami/model/config/adapter.rb +0 -116
- data/lib/hanami/model/config/mapper.rb +0 -45
- data/lib/hanami/model/mapper.rb +0 -124
- data/lib/hanami/model/mapping/attribute.rb +0 -85
- data/lib/hanami/model/mapping/coercers.rb +0 -314
- data/lib/hanami/model/mapping/collection.rb +0 -490
- data/lib/hanami/model/mapping/collection_coercer.rb +0 -79
@@ -0,0 +1,68 @@
|
|
1
|
+
require_relative 'abstract'
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
module Model
|
5
|
+
module Sql
|
6
|
+
module Consoles
|
7
|
+
# PostgreSQL adapter
|
8
|
+
#
|
9
|
+
# @since 0.7.0
|
10
|
+
# @api private
|
11
|
+
class Postgresql < Abstract
|
12
|
+
# @since 0.7.0
|
13
|
+
# @api private
|
14
|
+
COMMAND = 'psql'.freeze
|
15
|
+
|
16
|
+
# @since 0.7.0
|
17
|
+
# @api private
|
18
|
+
PASSWORD = 'PGPASSWORD'.freeze
|
19
|
+
|
20
|
+
# @since 0.7.0
|
21
|
+
# @api private
|
22
|
+
def connection_string
|
23
|
+
configure_password
|
24
|
+
concat(command, host, database, port, username)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# @since 0.7.0
|
30
|
+
# @api private
|
31
|
+
def command
|
32
|
+
COMMAND
|
33
|
+
end
|
34
|
+
|
35
|
+
# @since 0.7.0
|
36
|
+
# @api private
|
37
|
+
def host
|
38
|
+
" -h #{@uri.host}"
|
39
|
+
end
|
40
|
+
|
41
|
+
# @since 0.7.0
|
42
|
+
# @api private
|
43
|
+
def database
|
44
|
+
" -d #{database_name}"
|
45
|
+
end
|
46
|
+
|
47
|
+
# @since 0.7.0
|
48
|
+
# @api private
|
49
|
+
def port
|
50
|
+
" -p #{@uri.port}" unless @uri.port.nil?
|
51
|
+
end
|
52
|
+
|
53
|
+
# @since 0.7.0
|
54
|
+
# @api private
|
55
|
+
def username
|
56
|
+
" -U #{@uri.user}" unless @uri.user.nil?
|
57
|
+
end
|
58
|
+
|
59
|
+
# @since 0.7.0
|
60
|
+
# @api private
|
61
|
+
def configure_password
|
62
|
+
ENV[PASSWORD] = @uri.password unless @uri.password.nil?
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require_relative 'abstract'
|
2
|
+
require 'shellwords'
|
3
|
+
|
4
|
+
module Hanami
|
5
|
+
module Model
|
6
|
+
module Sql
|
7
|
+
module Consoles
|
8
|
+
# SQLite adapter
|
9
|
+
#
|
10
|
+
# @since 0.7.0
|
11
|
+
# @api private
|
12
|
+
class Sqlite < Abstract
|
13
|
+
# @since 0.7.0
|
14
|
+
# @api private
|
15
|
+
COMMAND = 'sqlite3'.freeze
|
16
|
+
|
17
|
+
# @since 0.7.0
|
18
|
+
# @api private
|
19
|
+
def connection_string
|
20
|
+
concat(command, ' ', host, database)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
# @since 0.7.0
|
26
|
+
# @api private
|
27
|
+
def command
|
28
|
+
COMMAND
|
29
|
+
end
|
30
|
+
|
31
|
+
# @since 0.7.0
|
32
|
+
# @api private
|
33
|
+
def host
|
34
|
+
@uri.host unless @uri.host.nil?
|
35
|
+
end
|
36
|
+
|
37
|
+
# @since 0.7.0
|
38
|
+
# @api private
|
39
|
+
def database
|
40
|
+
Shellwords.escape(@uri.path)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'hanami/entity/schema'
|
2
|
+
require 'hanami/model/types'
|
3
|
+
require 'hanami/model/association'
|
4
|
+
|
5
|
+
module Hanami
|
6
|
+
module Model
|
7
|
+
module Sql
|
8
|
+
module Entity
|
9
|
+
# SQL Entity schema
|
10
|
+
#
|
11
|
+
# This schema setup is automatic.
|
12
|
+
#
|
13
|
+
# Hanami looks at the database columns, associations and potentially to
|
14
|
+
# the mapping in the repository (optional, only for legacy databases).
|
15
|
+
#
|
16
|
+
# @since 0.7.0
|
17
|
+
# @api private
|
18
|
+
#
|
19
|
+
# @see Hanami::Entity::Schema
|
20
|
+
class Schema < Hanami::Entity::Schema
|
21
|
+
# Build a new instance of Schema according to database columns,
|
22
|
+
# associations and potentially to mapping defined by the repository.
|
23
|
+
#
|
24
|
+
# @param registry [Hash] a registry that keeps reference between
|
25
|
+
# entities klass and their underscored names
|
26
|
+
# @param relation [ROM::Relation] the database relation
|
27
|
+
# @param mapping [Hanami::Model::Mapping] the optional repository
|
28
|
+
# mapping
|
29
|
+
#
|
30
|
+
# @return [Hanami::Model::Sql::Entity::Schema] the schema
|
31
|
+
#
|
32
|
+
# @since 0.7.0
|
33
|
+
# @api private
|
34
|
+
def initialize(registry, relation, mapping)
|
35
|
+
attributes = build(registry, relation, mapping)
|
36
|
+
@schema = Types::Coercible::Hash.schema(attributes)
|
37
|
+
@attributes = Hash[attributes.map { |k, _| [k, true] }]
|
38
|
+
freeze
|
39
|
+
end
|
40
|
+
|
41
|
+
# Check if the attribute is known
|
42
|
+
#
|
43
|
+
# @param name [Symbol] the attribute name
|
44
|
+
#
|
45
|
+
# @return [TrueClass,FalseClass] the result of the check
|
46
|
+
#
|
47
|
+
# @since 0.7.0
|
48
|
+
# @api private
|
49
|
+
def attribute?(name)
|
50
|
+
attributes.key?(name)
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
# @since 0.7.0
|
56
|
+
# @api private
|
57
|
+
attr_reader :attributes
|
58
|
+
|
59
|
+
# Build the schema
|
60
|
+
#
|
61
|
+
# @param registry [Hash] a registry that keeps reference between
|
62
|
+
# entities klass and their underscored names
|
63
|
+
# @param relation [ROM::Relation] the database relation
|
64
|
+
# @param mapping [Hanami::Model::Mapping] the optional repository
|
65
|
+
# mapping
|
66
|
+
#
|
67
|
+
# @return [Dry::Types::Constructor] the inner schema
|
68
|
+
#
|
69
|
+
# @since 0.7.0
|
70
|
+
# @api private
|
71
|
+
def build(registry, relation, mapping)
|
72
|
+
build_attributes(relation, mapping).merge(
|
73
|
+
build_associations(registry, relation.associations)
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Extract a set of attributes from the database table or from the
|
78
|
+
# optional repository mapping.
|
79
|
+
#
|
80
|
+
# @param relation [ROM::Relation] the database relation
|
81
|
+
# @param mapping [Hanami::Model::Mapping] the optional repository
|
82
|
+
# mapping
|
83
|
+
#
|
84
|
+
# @return [Hash] a set of attributes
|
85
|
+
#
|
86
|
+
# @since 0.7.0
|
87
|
+
# @api private
|
88
|
+
def build_attributes(relation, mapping)
|
89
|
+
schema = relation.schema.to_h
|
90
|
+
schema.each_with_object({}) do |(attribute, type), result|
|
91
|
+
attribute = mapping.translate(attribute) if mapping.reverse?
|
92
|
+
result[attribute] = coercible(type)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Merge attributes and associations
|
97
|
+
#
|
98
|
+
# @param registry [Hash] a registry that keeps reference between
|
99
|
+
# entities klass and their underscored names
|
100
|
+
# @param associations [ROM::AssociationSet] a set of associations for
|
101
|
+
# the current relation
|
102
|
+
#
|
103
|
+
# @return [Hash] attributes with associations
|
104
|
+
#
|
105
|
+
# @since 0.7.0
|
106
|
+
# @api private
|
107
|
+
def build_associations(registry, associations)
|
108
|
+
associations.each_with_object({}) do |(name, association), result|
|
109
|
+
target = registry.fetch(name)
|
110
|
+
result[name] = Association.lookup(association).schema_type(target)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Converts given ROM type into coercible type for entity attribute
|
115
|
+
#
|
116
|
+
# @since 0.7.0
|
117
|
+
# @api private
|
118
|
+
def coercible(type)
|
119
|
+
Types::Schema.coercible(type)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'hanami/model/types'
|
2
|
+
require 'rom/types'
|
3
|
+
|
4
|
+
module Hanami
|
5
|
+
module Model
|
6
|
+
module Sql
|
7
|
+
# Types definitions for SQL databases
|
8
|
+
#
|
9
|
+
# @since 0.7.0
|
10
|
+
module Types
|
11
|
+
include Dry::Types.module
|
12
|
+
|
13
|
+
# Types for schema definitions
|
14
|
+
#
|
15
|
+
# @since 0.7.0
|
16
|
+
module Schema
|
17
|
+
require 'hanami/model/sql/types/schema/coercions'
|
18
|
+
|
19
|
+
String = Types::Optional::Coercible::String
|
20
|
+
|
21
|
+
Int = Types::Strict::Nil | Types::Int.constructor(Coercions.method(:int))
|
22
|
+
Float = Types::Strict::Nil | Types::Float.constructor(Coercions.method(:float))
|
23
|
+
Decimal = Types::Strict::Nil | Types::Float.constructor(Coercions.method(:decimal))
|
24
|
+
|
25
|
+
Bool = Types::Strict::Nil | Types::Strict::Bool
|
26
|
+
|
27
|
+
Date = Types::Strict::Nil | Types::Date.constructor(Coercions.method(:date))
|
28
|
+
DateTime = Types::Strict::Nil | Types::DateTime.constructor(Coercions.method(:datetime))
|
29
|
+
Time = Types::Strict::Nil | Types::Time.constructor(Coercions.method(:time))
|
30
|
+
|
31
|
+
Array = Types::Strict::Nil | Types::Array.constructor(Coercions.method(:array))
|
32
|
+
Hash = Types::Strict::Nil | Types::Array.constructor(Coercions.method(:hash))
|
33
|
+
|
34
|
+
# @since 0.7.0
|
35
|
+
# @api private
|
36
|
+
MAPPING = {
|
37
|
+
Types::String.with(meta: {}) => Schema::String,
|
38
|
+
Types::Int.with(meta: {}) => Schema::Int,
|
39
|
+
Types::Float.with(meta: {}) => Schema::Float,
|
40
|
+
Types::Decimal.with(meta: {}) => Schema::Decimal,
|
41
|
+
Types::Bool.with(meta: {}) => Schema::Bool,
|
42
|
+
Types::Date.with(meta: {}) => Schema::Date,
|
43
|
+
Types::DateTime.with(meta: {}) => Schema::DateTime,
|
44
|
+
Types::Time.with(meta: {}) => Schema::Time,
|
45
|
+
Types::Array.with(meta: {}) => Schema::Array,
|
46
|
+
Types::Hash.with(meta: {}) => Schema::Hash,
|
47
|
+
Types::String.optional.with(meta: {}) => Schema::String,
|
48
|
+
Types::Int.optional.with(meta: {}) => Schema::Int,
|
49
|
+
Types::Float.optional.with(meta: {}) => Schema::Float,
|
50
|
+
Types::Decimal.optional.with(meta: {}) => Schema::Decimal,
|
51
|
+
Types::Bool.optional.with(meta: {}) => Schema::Bool,
|
52
|
+
Types::Date.optional.with(meta: {}) => Schema::Date,
|
53
|
+
Types::DateTime.optional.with(meta: {}) => Schema::DateTime,
|
54
|
+
Types::Time.optional.with(meta: {}) => Schema::Time,
|
55
|
+
Types::Array.optional.with(meta: {}) => Schema::Array,
|
56
|
+
Types::Hash.optional.with(meta: {}) => Schema::Hash
|
57
|
+
}.freeze
|
58
|
+
|
59
|
+
# Convert given type into coercible
|
60
|
+
#
|
61
|
+
# @since 0.7.0
|
62
|
+
# @api private
|
63
|
+
def self.coercible(type)
|
64
|
+
return type if type.constrained?
|
65
|
+
MAPPING.fetch(type.with(meta: {}), type)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Coercer for SQL associations target
|
69
|
+
#
|
70
|
+
# @since 0.7.0
|
71
|
+
# @api private
|
72
|
+
class AssociationType < Hanami::Model::Types::Schema::CoercibleType
|
73
|
+
# Check if value can be coerced
|
74
|
+
#
|
75
|
+
# @param value [Object] the value
|
76
|
+
#
|
77
|
+
# @return [TrueClass,FalseClass] the result of the check
|
78
|
+
#
|
79
|
+
# @since 0.7.0
|
80
|
+
# @api private
|
81
|
+
def valid?(value)
|
82
|
+
value.inspect =~ /\[#{primitive}\]/ || super
|
83
|
+
end
|
84
|
+
|
85
|
+
# @since 0.7.0
|
86
|
+
# @api private
|
87
|
+
def success(*args)
|
88
|
+
result(Dry::Types::Result::Success, primitive.new(args.first.to_h))
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
require 'hanami/utils/string'
|
2
|
+
|
3
|
+
module Hanami
|
4
|
+
module Model
|
5
|
+
module Sql
|
6
|
+
module Types
|
7
|
+
module Schema
|
8
|
+
# Coercions for schema types
|
9
|
+
#
|
10
|
+
# @since 0.7.0
|
11
|
+
# @api private
|
12
|
+
#
|
13
|
+
# rubocop:disable Metrics/MethodLength
|
14
|
+
module Coercions
|
15
|
+
# Coerces given argument into Integer
|
16
|
+
#
|
17
|
+
# @param arg [#to_i,#to_int] the argument to coerce
|
18
|
+
#
|
19
|
+
# @return [Integer] the result of the coercion
|
20
|
+
#
|
21
|
+
# @raise [ArgumentError] if the coercion fails
|
22
|
+
#
|
23
|
+
# @since 0.7.0
|
24
|
+
# @api private
|
25
|
+
def self.int(arg)
|
26
|
+
case arg
|
27
|
+
when ::Integer
|
28
|
+
arg
|
29
|
+
when ::Float, ::BigDecimal, ::String, ::Hanami::Utils::String, ->(a) { a.respond_to?(:to_int) }
|
30
|
+
::Kernel.Integer(arg)
|
31
|
+
else
|
32
|
+
raise ArgumentError.new("invalid value for Integer(): #{arg.inspect}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Coerces given argument into Float
|
37
|
+
#
|
38
|
+
# @param arg [#to_f] the argument to coerce
|
39
|
+
#
|
40
|
+
# @return [Float] the result of the coercion
|
41
|
+
#
|
42
|
+
# @raise [ArgumentError] if the coercion fails
|
43
|
+
#
|
44
|
+
# @since 0.7.0
|
45
|
+
# @api private
|
46
|
+
def self.float(arg)
|
47
|
+
case arg
|
48
|
+
when ::Float
|
49
|
+
arg
|
50
|
+
when ::Integer, ::BigDecimal, ::String, ::Hanami::Utils::String, ->(a) { a.respond_to?(:to_f) && !a.is_a?(::Time) }
|
51
|
+
::Kernel.Float(arg)
|
52
|
+
else
|
53
|
+
raise ArgumentError.new("invalid value for Float(): #{arg.inspect}")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Coerces given argument into BigDecimal
|
58
|
+
#
|
59
|
+
# @param arg [#to_d] the argument to coerce
|
60
|
+
#
|
61
|
+
# @return [BigDecimal] the result of the coercion
|
62
|
+
#
|
63
|
+
# @raise [ArgumentError] if the coercion fails
|
64
|
+
#
|
65
|
+
# @since 0.7.0
|
66
|
+
# @api private
|
67
|
+
def self.decimal(arg)
|
68
|
+
case arg
|
69
|
+
when ::BigDecimal
|
70
|
+
arg
|
71
|
+
when ::Integer, ::Float, ::String, ::Hanami::Utils::String
|
72
|
+
::BigDecimal.new(arg, ::Float::DIG)
|
73
|
+
when ->(a) { a.respond_to?(:to_d) }
|
74
|
+
arg.to_d
|
75
|
+
else
|
76
|
+
raise ArgumentError.new("invalid value for BigDecimal(): #{arg.inspect}")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Coerces given argument into Date
|
81
|
+
#
|
82
|
+
# @param arg [#to_date,String] the argument to coerce
|
83
|
+
#
|
84
|
+
# @return [Date] the result of the coercion
|
85
|
+
#
|
86
|
+
# @raise [ArgumentError] if the coercion fails
|
87
|
+
#
|
88
|
+
# @since 0.7.0
|
89
|
+
# @api private
|
90
|
+
def self.date(arg)
|
91
|
+
case arg
|
92
|
+
when ::Date
|
93
|
+
arg
|
94
|
+
when ::String, ::Hanami::Utils::String
|
95
|
+
::Date.parse(arg)
|
96
|
+
when ::Time, ::DateTime, ->(a) { a.respond_to?(:to_date) }
|
97
|
+
arg.to_date
|
98
|
+
else
|
99
|
+
raise ArgumentError.new("invalid value for Date(): #{arg.inspect}")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Coerces given argument into DateTime
|
104
|
+
#
|
105
|
+
# @param arg [#to_datetime,String] the argument to coerce
|
106
|
+
#
|
107
|
+
# @return [DateTime] the result of the coercion
|
108
|
+
#
|
109
|
+
# @raise [ArgumentError] if the coercion fails
|
110
|
+
#
|
111
|
+
# @since 0.7.0
|
112
|
+
# @api private
|
113
|
+
def self.datetime(arg)
|
114
|
+
case arg
|
115
|
+
when ::DateTime
|
116
|
+
arg
|
117
|
+
when ::String, ::Hanami::Utils::String
|
118
|
+
::DateTime.parse(arg)
|
119
|
+
when ::Date, ::Time, ->(a) { a.respond_to?(:to_datetime) }
|
120
|
+
arg.to_datetime
|
121
|
+
else
|
122
|
+
raise ArgumentError.new("invalid value for DateTime(): #{arg.inspect}")
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Coerces given argument into Time
|
127
|
+
#
|
128
|
+
# @param arg [#to_time,String] the argument to coerce
|
129
|
+
#
|
130
|
+
# @return [Time] the result of the coercion
|
131
|
+
#
|
132
|
+
# @raise [ArgumentError] if the coercion fails
|
133
|
+
#
|
134
|
+
# @since 0.7.0
|
135
|
+
# @api private
|
136
|
+
def self.time(arg)
|
137
|
+
case arg
|
138
|
+
when ::Time
|
139
|
+
arg
|
140
|
+
when ::String, ::Hanami::Utils::String
|
141
|
+
::Time.parse(arg)
|
142
|
+
when ::Date, ::DateTime, ->(a) { a.respond_to?(:to_time) }
|
143
|
+
arg.to_time
|
144
|
+
when ::Integer
|
145
|
+
::Time.at(arg)
|
146
|
+
else
|
147
|
+
raise ArgumentError.new("invalid value for Time(): #{arg.inspect}")
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Coerces given argument into Array
|
152
|
+
#
|
153
|
+
# @param arg [#to_ary] the argument to coerce
|
154
|
+
#
|
155
|
+
# @return [Array] the result of the coercion
|
156
|
+
#
|
157
|
+
# @raise [ArgumentError] if the coercion fails
|
158
|
+
#
|
159
|
+
# @since 0.7.0
|
160
|
+
# @api private
|
161
|
+
def self.array(arg)
|
162
|
+
case arg
|
163
|
+
when ::Array
|
164
|
+
arg
|
165
|
+
when ->(a) { a.respond_to?(:to_ary) }
|
166
|
+
::Kernel.Array(arg)
|
167
|
+
else
|
168
|
+
raise ArgumentError.new("invalid value for Array(): #{arg.inspect}")
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# Coerces given argument into Hash
|
173
|
+
#
|
174
|
+
# @param arg [#to_hash] the argument to coerce
|
175
|
+
#
|
176
|
+
# @return [Hash] the result of the coercion
|
177
|
+
#
|
178
|
+
# @raise [ArgumentError] if the coercion fails
|
179
|
+
#
|
180
|
+
# @since 0.7.0
|
181
|
+
# @api private
|
182
|
+
def self.hash(arg)
|
183
|
+
case arg
|
184
|
+
when ::Hash
|
185
|
+
arg
|
186
|
+
when ->(a) { a.respond_to?(:to_hash) }
|
187
|
+
::Kernel.Hash(arg)
|
188
|
+
else
|
189
|
+
raise ArgumentError.new("invalid value for Hash(): #{arg.inspect}")
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
# rubocop:enable Metrics/MethodLength
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|