rom-files 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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