rom-files 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.
Files changed (122) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +9 -0
  3. data/.gitignore +11 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +112 -0
  6. data/.rubocop_todo.yml +7 -0
  7. data/.ruby-version +1 -0
  8. data/.simplecov +6 -0
  9. data/.travis.yml +24 -0
  10. data/.yardopts +6 -0
  11. data/CHANGELOG.md +10 -0
  12. data/Gemfile +25 -0
  13. data/Guardfile +48 -0
  14. data/LICENSE.md +21 -0
  15. data/README.md +44 -0
  16. data/Rakefile +37 -0
  17. data/Roadmap.taskpaper +44 -0
  18. data/bin/_guard-core +21 -0
  19. data/bin/console +7 -0
  20. data/bin/guard +21 -0
  21. data/bin/rake +21 -0
  22. data/bin/rspec +21 -0
  23. data/bin/yard +21 -0
  24. data/bin/yardoc +21 -0
  25. data/bin/yri +21 -0
  26. data/lib/dry/types/pathname.rb +25 -0
  27. data/lib/pathname/extensions.rb +32 -0
  28. data/lib/pathname/extensions/constants.rb +12 -0
  29. data/lib/pathname/extensions/explode.rb +27 -0
  30. data/lib/pathname/extensions/ext.rb +28 -0
  31. data/lib/pathname/extensions/partial.rb +30 -0
  32. data/lib/pathname/extensions/pathmap.rb +128 -0
  33. data/lib/rom-files.rb +3 -0
  34. data/lib/rom/files.rb +28 -0
  35. data/lib/rom/files/associations.rb +6 -0
  36. data/lib/rom/files/associations/many_to_many.rb +12 -0
  37. data/lib/rom/files/associations/many_to_one.rb +12 -0
  38. data/lib/rom/files/associations/one_to_many.rb +12 -0
  39. data/lib/rom/files/associations/one_to_one.rb +12 -0
  40. data/lib/rom/files/attribute.rb +21 -0
  41. data/lib/rom/files/commands/create.rb +18 -0
  42. data/lib/rom/files/commands/delete.rb +17 -0
  43. data/lib/rom/files/commands/update.rb +17 -0
  44. data/lib/rom/files/connection.rb +120 -0
  45. data/lib/rom/files/constants.rb +16 -0
  46. data/lib/rom/files/dataset.rb +89 -0
  47. data/lib/rom/files/dataset/filtering.rb +96 -0
  48. data/lib/rom/files/dataset/mime_type.rb +44 -0
  49. data/lib/rom/files/dataset/paths.rb +79 -0
  50. data/lib/rom/files/dataset/sorting.rb +27 -0
  51. data/lib/rom/files/extensions.rb +30 -0
  52. data/lib/rom/files/extensions/gem.rb +29 -0
  53. data/lib/rom/files/extensions/gem/relations/documentations.rb +18 -0
  54. data/lib/rom/files/extensions/gem/relations/executables.rb +20 -0
  55. data/lib/rom/files/extensions/gem/relations/implementations.rb +29 -0
  56. data/lib/rom/files/extensions/gem/relations/specifications.rb +29 -0
  57. data/lib/rom/files/extensions/markdown/attributes_inferrer.rb +20 -0
  58. data/lib/rom/files/extensions/markdown/types.rb +18 -0
  59. data/lib/rom/files/extensions/markup/attributes_inferrer.rb +32 -0
  60. data/lib/rom/files/extensions/ruby/attributes_inferrer.rb +21 -0
  61. data/lib/rom/files/extensions/ruby/types.rb +45 -0
  62. data/lib/rom/files/extensions/text/attributes_inferrer.rb +20 -0
  63. data/lib/rom/files/gateway.rb +63 -0
  64. data/lib/rom/files/plugins/configuration/gem.rb +30 -0
  65. data/lib/rom/files/plugins/relation/instrumentation.rb +28 -0
  66. data/lib/rom/files/plugins/schema/contents.rb +72 -0
  67. data/lib/rom/files/plugins/schema/mime.rb +59 -0
  68. data/lib/rom/files/plugins/schema/shebang.rb +79 -0
  69. data/lib/rom/files/plugins/schema/stat.rb +108 -0
  70. data/lib/rom/files/relation.rb +143 -0
  71. data/lib/rom/files/schema.rb +77 -0
  72. data/lib/rom/files/schema/attributes_inferrer.rb +79 -0
  73. data/lib/rom/files/schema/inferrer.rb +36 -0
  74. data/lib/rom/files/types.rb +37 -0
  75. data/lib/rom/files/version.rb +7 -0
  76. data/rom-files.gemspec +48 -0
  77. data/spec/integration/rom/files/gateway_spec.rb +28 -0
  78. data/spec/integration/rom/files/gem_spec.rb +98 -0
  79. data/spec/integration/rom/files/relations_spec.rb +63 -0
  80. data/spec/integration/rom/files/schema/inferrer_spec.rb +77 -0
  81. data/spec/lib/dry/types/pathname_spec.rb +50 -0
  82. data/spec/lib/pathname/extensions/explode_spec.rb +25 -0
  83. data/spec/lib/pathname/extensions/ext_spec.rb +33 -0
  84. data/spec/lib/pathname/extensions/partial_spec.rb +17 -0
  85. data/spec/lib/pathname/extensions/pathmap_spec.rb +147 -0
  86. data/spec/lib/rom/files/attribute_spec.rb +43 -0
  87. data/spec/lib/rom/files/connection_spec.rb +76 -0
  88. data/spec/lib/rom/files/dataset/inside_spec.rb +22 -0
  89. data/spec/lib/rom/files/dataset/mime_type_spec.rb +23 -0
  90. data/spec/lib/rom/files/dataset/recursive_question_mark_spec.rb +42 -0
  91. data/spec/lib/rom/files/dataset/recursive_spec.rb +29 -0
  92. data/spec/lib/rom/files/dataset/reject_append_spec.rb +68 -0
  93. data/spec/lib/rom/files/dataset/reject_spec.rb +26 -0
  94. data/spec/lib/rom/files/dataset/select_append_spec.rb +69 -0
  95. data/spec/lib/rom/files/dataset/select_spec.rb +38 -0
  96. data/spec/lib/rom/files/dataset/sort_spec.rb +22 -0
  97. data/spec/lib/rom/files/dataset_spec.rb +52 -0
  98. data/spec/lib/rom/files/extensions/text/attributes_inferrer_spec.rb +54 -0
  99. data/spec/lib/rom/files/gateway_spec.rb +39 -0
  100. data/spec/lib/rom/files/plugins/schema/contents_spec.rb +66 -0
  101. data/spec/lib/rom/files/plugins/schema/mime_spec.rb +66 -0
  102. data/spec/lib/rom/files/plugins/schema/stat_spec.rb +109 -0
  103. data/spec/lib/rom/files/relation/pluck_spec.rb +20 -0
  104. data/spec/lib/rom/files/relation/reject_spec.rb +22 -0
  105. data/spec/lib/rom/files/relation/select_spec.rb +35 -0
  106. data/spec/lib/rom/files/relation/sort_spec.rb +21 -0
  107. data/spec/lib/rom/files/relation/to_a_spec.rb +39 -0
  108. data/spec/lib/rom/files/relation_spec.rb +10 -0
  109. data/spec/lib/rom/files/schema/attributes_inferrer_spec.rb +45 -0
  110. data/spec/lib/rom/files/schema/inferrer_spec.rb +29 -0
  111. data/spec/lib/rom/files/schema_spec.rb +109 -0
  112. data/spec/lib/rom/files/types/mime_type_spec.rb +9 -0
  113. data/spec/lib/rom/files/types/path_spec.rb +10 -0
  114. data/spec/lib/rom/files/types_spec.rb +6 -0
  115. data/spec/shared/rom/files/files_setup.rb +19 -0
  116. data/spec/shared/rom/files/filesystem_setup.rb +10 -0
  117. data/spec/shared/rom/files/gateway_setup.rb +17 -0
  118. data/spec/shared/rom/files/media_dataset.rb +10 -0
  119. data/spec/shared/rom/files/media_files.rb +17 -0
  120. data/spec/shared/rom/files/media_relation.rb +30 -0
  121. data/spec/spec_helper.rb +10 -0
  122. metadata +421 -0
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../markup/attributes_inferrer'
4
+
5
+ module ROM
6
+ module Files
7
+ module Extensions
8
+ module Text
9
+ class AttributesInferrer < Markup::AttributesInferrer
10
+ # @return [Dry::Types::Definition]
11
+ def markup_type
12
+ Types::String
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ Schema::AttributesInferrer.register 'text/plain', Extensions::Text::AttributesInferrer.new.freeze
19
+ end
20
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require_relative 'connection'
5
+ require_relative 'extensions'
6
+
7
+ module ROM
8
+ module Files
9
+ # Files gateway interface
10
+ #
11
+ # @example
12
+ # gateway = ROM::Files::Gateway.new('.')
13
+ # gateway.dataset(:lib)
14
+ # gateway[:lib].insert(name: 'rom.rb')
15
+ #
16
+ # @api public
17
+ class Gateway < ROM::Gateway
18
+ extend Forwardable
19
+
20
+ adapter :files
21
+
22
+ # @!attribute [r] connection
23
+ # @return [Connection]
24
+
25
+ # @param root [Pathname, #to_s]
26
+ # @param extensions [Array<Symbol>, Symbol]
27
+ def initialize(root = Pathname.pwd, extensions: [])
28
+ @connection = Connection.new(root)
29
+ Files.load_extensions(*Array(extensions))
30
+ end
31
+
32
+ # @return [Object] default logger
33
+ #
34
+ # @api public
35
+ attr_reader :logger
36
+
37
+ # Set default logger for the gateway
38
+ #
39
+ # @param logger [Logger] object
40
+ #
41
+ # @api public
42
+ def use_logger(logger)
43
+ @logger = logger
44
+ end
45
+
46
+ # @param name [Pathname, #to_s]
47
+ # @return [Dataset]
48
+ def dataset(name)
49
+ self[name] || connection.create_dataset(name)
50
+ end
51
+
52
+ # @!method []
53
+ # @param (see Connection#[])
54
+ # @return (see Connection#[])
55
+ def_instance_delegators :connection, :[]
56
+
57
+ # @!method dataset?
58
+ # @param (see Connection#key?)
59
+ # @return (see Connection#key?)
60
+ def_instance_delegator :connection, :key?, :dataset?
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rom/files/extensions'
4
+
5
+ module ROM
6
+ module Files
7
+ module Plugins
8
+ module Configuration
9
+ module Gem
10
+ # Provide methods for registering files relations with common gem setup
11
+ #
12
+ # @param configuration [ROM::Configuration]
13
+ # @param relations [Boolean]
14
+ # @return [ROM::Configuration]
15
+ def self.apply(configuration, relations: true, **options)
16
+ configuration.extend Methods
17
+ configuration.register_gem_relations(**options) if relations
18
+ end
19
+
20
+ module Methods
21
+ def register_gem_relations(**options)
22
+ Files.load_extensions(:gem)
23
+ Files::Extensions::Gem.register_extension(self, **options)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rom/plugins/relation/instrumentation'
4
+
5
+ module ROM
6
+ module Files
7
+ module Plugins
8
+ module Relation
9
+ # @api private
10
+ module Instrumentation
11
+ def self.included(klass)
12
+ super
13
+
14
+ klass.class_eval do
15
+ include ROM::Plugins::Relation::Instrumentation
16
+
17
+ # @api private
18
+ # @param [ROM::Files::Relation] relation
19
+ def notification_payload(relation)
20
+ super.merge(**relation.dataset.options)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rom/files/constants'
4
+ require 'rom/files/types'
5
+
6
+ module ROM
7
+ module Files
8
+ module Plugins
9
+ module Schema
10
+ # A plugin for automatically adding contents of file
11
+ # to the schema definition
12
+ #
13
+ # @example Generic `DATA` field with String type
14
+ # schema do
15
+ # use :contents
16
+ # end
17
+ #
18
+ # @example Specify another type
19
+ # schema do
20
+ # use :contents, type: Types::YAML
21
+ # end
22
+ #
23
+ # @example Specify another name
24
+ # # using other types
25
+ # schema do
26
+ # use :contents, name: :contents
27
+ # end
28
+ #
29
+ # @api public
30
+ module Contents
31
+ NAME = Files::DATA
32
+ TYPE = Types::String
33
+
34
+ # @api private
35
+ def self.apply(schema, name: NAME, type: TYPE)
36
+ contents = type.meta(name: name, source: schema.name, DATA: true)
37
+
38
+ schema.attributes.concat(
39
+ schema.class.attributes([contents], schema.attr_class)
40
+ )
41
+ end
42
+
43
+ # @api private
44
+ module DSL
45
+ # Sets non-default contents attribute
46
+ #
47
+ # @example Set custom attribute name
48
+ # schema do
49
+ # use :contents
50
+ # contents :contents
51
+ # end
52
+ #
53
+ # @example Set custom type
54
+ # schema do
55
+ # use :contents
56
+ # contents type: Types::JSON
57
+ # end
58
+ #
59
+ # @api public
60
+ def contents(name = NAME, inline_type = TYPE, type: inline_type)
61
+ options = plugin_options(:contents)
62
+ options[:name] = name
63
+ options[:type] = type
64
+
65
+ self
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rom/files/constants'
4
+ require 'rom/files/types'
5
+ require 'mime/types/full'
6
+
7
+ module ROM
8
+ module Files
9
+ module Plugins
10
+ module Schema
11
+ # A plugin for obtaining MIME-type of file using its name
12
+ #
13
+ # @example Generic `mime_type` field
14
+ # schema do
15
+ # use :mime_type
16
+ # end
17
+ #
18
+ # @api public
19
+ module Mime
20
+ PROC = ->(path) { MIME::Types.type_for(path.basename.to_s).first }
21
+ TYPE = Types::MimeType.optional
22
+
23
+ # @api private
24
+ def self.apply(schema, name: :mime_type, type: TYPE)
25
+ mime_type = type.meta(
26
+ name: name,
27
+ __proc__: PROC,
28
+ source: schema.name
29
+ )
30
+
31
+ schema.attributes.concat(
32
+ schema.class.attributes([mime_type], schema.attr_class)
33
+ )
34
+ end
35
+
36
+ # @api private
37
+ module DSL
38
+ # Sets non-default contents attribute
39
+ #
40
+ # @example Set custom attribute name `#type` for MIME-type
41
+ # schema do
42
+ # use :mime
43
+ # mime :type
44
+ # end
45
+ #
46
+ # @api public
47
+ def mime(name = :mime_type, inline_type = TYPE, type: inline_type)
48
+ options = plugin_options(:mime)
49
+ options[:name] = name
50
+ options[:type] = type
51
+
52
+ self
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rom/files/constants'
4
+ require 'rom/files/types'
5
+
6
+ module ROM
7
+ module Files
8
+ module Plugins
9
+ module Schema
10
+ # A plugin for automatically adding shebang of file
11
+ # to the schema definition
12
+ #
13
+ # @example Generic `DATA` field with String type
14
+ # schema do
15
+ # use :shebang
16
+ # end
17
+ #
18
+ # @example Specify another type
19
+ # schema do
20
+ # use :shebang, type: Types::YAML
21
+ # end
22
+ #
23
+ # @example Specify another name
24
+ # # using other types
25
+ # schema do
26
+ # use :shebang, name: :shebang
27
+ # end
28
+ #
29
+ # @api public
30
+ module Shebang
31
+ TYPE = Types::String
32
+ NAME = :run_with
33
+
34
+ # @param path [Pathname]
35
+ # @return [String, nil]
36
+ def self.read_shebang(path)
37
+ shebang = path.readlines.first || ''
38
+ shebang[2..-1].chomp if shebang.match?(/\A#!/)
39
+ end
40
+
41
+ # @api private
42
+ def self.apply(schema, name: NAME, type: TYPE)
43
+ shebang = type.meta(name: name, source: schema.name, __proc__: method(:read_shebang))
44
+
45
+ schema.attributes.concat(
46
+ schema.class.attributes([shebang], schema.attr_class)
47
+ )
48
+ end
49
+
50
+ # @api private
51
+ module DSL
52
+ # Sets non-default shebang attribute
53
+ #
54
+ # @example Set custom attribute name
55
+ # schema do
56
+ # use :shebang
57
+ # shebang :shebang
58
+ # end
59
+ #
60
+ # @example Set custom type
61
+ # schema do
62
+ # use :shebang
63
+ # shebang type: Types::JSON
64
+ # end
65
+ #
66
+ # @api public
67
+ def shebang(name = NAME, inline = TYPE, type: inline)
68
+ options = plugin_options(:shebang)
69
+ options[:name] = name
70
+ options[:type] = type
71
+
72
+ self
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rom/files/types'
4
+
5
+ module ROM
6
+ module Files
7
+ module Plugins
8
+ module Schema
9
+ # A plugin for automatically adding stat properties of file
10
+ # to the schema definition
11
+ #
12
+ # @example Generic `__stat__` field with String type
13
+ # schema do
14
+ # use :stat
15
+ # end
16
+ #
17
+ # @example Specify another set of properties
18
+ # schema do
19
+ # use :stat, properties: %i[]
20
+ # end
21
+ #
22
+ # @api public
23
+ module Stat
24
+ NAME = :stat
25
+
26
+ TYPES = {
27
+ atime: Types::Time,
28
+ basename: Types::String,
29
+ birthtime: Types::Time,
30
+ blksize: Types::Int.optional,
31
+ blocks: Types::Int.optional,
32
+ ctime: Types::Time,
33
+ dev: Types::Int,
34
+ dev_major: Types::Int,
35
+ dev_minor: Types::Int,
36
+ ftype: Types::FileType,
37
+ gid: Types::Int,
38
+ ino: Types::Int,
39
+ mode: Types::Int,
40
+ mtime: Types::Time,
41
+ nlink: Types::Int,
42
+ rdev: Types::Int,
43
+ rdev_major: Types::Int,
44
+ rdev_minor: Types::Int,
45
+ size: Types::Int,
46
+ uid: Types::Int
47
+ }.freeze
48
+
49
+ ALIASES = {
50
+ accessed_at: :atime,
51
+ changed_at: :ctime,
52
+ updated_at: :mtime,
53
+ created_at: :birthtime,
54
+ type: :ftype
55
+ }.freeze
56
+
57
+ class << self
58
+ # @api private
59
+ def apply(schema, name: NAME, stats: EMPTY_ARRAY, aliases: EMPTY_HASH)
60
+ attributes = []
61
+ attributes = [build_property(schema, name, type: Types::FileStat)] if name
62
+ attributes += stats.map { |stat| build_property(schema, stat) }
63
+ attributes += aliases.map do |as, stat|
64
+ build_property(schema, as, stat: stat)
65
+ end
66
+
67
+ schema.attributes.concat(
68
+ schema.class.attributes(attributes, schema.attr_class)
69
+ )
70
+ end
71
+
72
+ private
73
+
74
+ def build_property(schema, name, stat: ALIASES[name] || name, type: TYPES[stat])
75
+ raise ArgumentError, "Unknown property #{(stat || name).inspect}" unless type
76
+ type.meta(name: name, source: schema.name, __stat__: (stat == NAME) || stat)
77
+ end
78
+ end
79
+
80
+ # @api private
81
+ module DSL
82
+ # @example Sets non-default list of stat properties
83
+ # schema do
84
+ # use :stat
85
+ # stat :basename
86
+ # end
87
+ #
88
+ # @example Sets list of aliased properties
89
+ # schema do
90
+ # use :stat
91
+ # stat aliased: { created_at: :ctime }
92
+ # end
93
+ #
94
+ # @api public
95
+ def stat(name = NAME, stats: EMPTY_ARRAY, aliases: EMPTY_HASH)
96
+ options = plugin_options(:stat)
97
+ options[:name] = name
98
+ options[:stats] = stats
99
+ options[:aliases] = aliases
100
+
101
+ self
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end