hanami-model 0.6.1 → 0.7.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.
- 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
|