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,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rom/memory/dataset'
4
+ require_relative '../constants'
5
+
6
+ module ROM
7
+ module Files
8
+ class Dataset < Memory::Dataset
9
+ module MimeType
10
+ def self.included(other)
11
+ super(other)
12
+ other.module_eval do
13
+ option :mime_type, Types::MimeType.optional,
14
+ default: -> { nil }
15
+
16
+ prepend Initializer
17
+ end
18
+ end
19
+
20
+ module Initializer
21
+ def initialize(data, mime_type: nil, include_patterns: ALL, **options)
22
+ if mime_type && include_patterns.all? { |pattern| pattern !~ /\./ }
23
+ include_patterns = include_patterns.inject([]) do |result, pattern|
24
+ result + mime_type.extensions.map { |ext| "#{pattern}.#{ext}" }
25
+ end
26
+ end
27
+ super(data, mime_type: mime_type, include_patterns: include_patterns, **options)
28
+ end
29
+ end
30
+
31
+ # @!attribute [r] mime_type
32
+ # MIME-type of files to include
33
+ # @return [MIME::Type?]
34
+
35
+ # @param type [String, nil]
36
+ # @return [Dataset]
37
+ def mime(type = nil)
38
+ type = Types::MimeType[type] if type
39
+ with(mime_type: type)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rom/memory/dataset'
4
+ require 'rom/files/constants'
5
+
6
+ module ROM
7
+ module Files
8
+ class Dataset < Memory::Dataset
9
+ module Paths
10
+ def self.included(other)
11
+ super(other)
12
+ other.extend ClassInterface
13
+ end
14
+
15
+ module ClassInterface
16
+ # @return [Proc]
17
+ def row_proc
18
+ ->(path) { Hash[ID => path] }
19
+ end
20
+ end
21
+
22
+ # @!attribute [r] row_proc
23
+ # @return [Proc]
24
+
25
+ # @return [Array<Pathname>]
26
+ def paths
27
+ connection.search(search_patterns, exclude_patterns: exclude_patterns, sorting: sorting, path: path)
28
+ end
29
+
30
+ # Pluck values from a pathname property
31
+ #
32
+ # @overload pluck(field)
33
+ #
34
+ # @example Usage with Symbol
35
+ # users.pluck(:extname).uniq
36
+ # # %w[.rb .rbw]
37
+ #
38
+ # @param [#to_proc, nil] field A name of the property for extracting values from pathname
39
+ #
40
+ # @overload pluck { |pathname| ... }
41
+ #
42
+ # @example Usage with block
43
+ # users.pluck { |pathname| pathname.basename.to_s }
44
+ # # [1, 2, 3]
45
+ #
46
+ # @return [Array]
47
+ #
48
+ # @api public
49
+ def pluck(field = nil, &block)
50
+ block ||= field&.to_proc || row_proc
51
+ paths.map(&block)
52
+ end
53
+
54
+ # @return [Array<Hash{Symbol => Pathname, String}>]
55
+ def data
56
+ pluck(row_proc)
57
+ end
58
+
59
+ alias to_a data
60
+ alias to_ary to_a
61
+
62
+ # Iterate over data using row_proc
63
+ #
64
+ # @return [Enumerator, Array] if block is not given
65
+ #
66
+ # @api private
67
+ def each
68
+ return to_enum unless block_given?
69
+ paths.each { |tuple| yield(row_proc[tuple]) }
70
+ end
71
+
72
+ # @return [Integer]
73
+ def count
74
+ to_a.size
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rom/memory/dataset'
4
+
5
+ module ROM
6
+ module Files
7
+ class Dataset < Memory::Dataset
8
+ module Sorting
9
+ def self.included(other)
10
+ super(other)
11
+ other.module_eval do
12
+ option :sorting, Types::Symbol.optional,
13
+ default: proc { nil }
14
+ end
15
+ end
16
+
17
+ # @!attribute [r] sorting
18
+ # @return [Symbol, Proc, nil]
19
+
20
+ # @return [Dataset]
21
+ def sort(sorting = :to_s)
22
+ with(sorting: sorting)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/core/extensions'
4
+
5
+ module ROM
6
+ module Files
7
+ module Extensions
8
+ end
9
+
10
+ extend Dry::Core::Extensions
11
+
12
+ register_extension :text do
13
+ require_relative 'extensions/text/attributes_inferrer'
14
+ end
15
+
16
+ register_extension :markdown do
17
+ require_relative 'extensions/markdown/attributes_inferrer'
18
+ end
19
+
20
+ register_extension :ruby do
21
+ require_relative 'extensions/ruby/attributes_inferrer'
22
+ end
23
+
24
+ register_extension :gem do
25
+ require 'pathname/extensions'
26
+ Pathname.load_extensions :pathmap
27
+ require_relative 'extensions/gem'
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rom/files/extensions'
4
+ require_relative 'gem/relations/documentations'
5
+ require_relative 'gem/relations/executables'
6
+ require_relative 'gem/relations/implementations'
7
+ require_relative 'gem/relations/specifications'
8
+
9
+ module ROM
10
+ module Files
11
+ load_extensions :ruby, :markdown
12
+
13
+ module Extensions
14
+ module Gem
15
+ # @param config [ROM::Configuration]
16
+ def self.register_extension(config, gateway: :default)
17
+ relations = [Relations::Documentations,
18
+ Relations::Executables,
19
+ Relations::Implementations,
20
+ Relations::Specifications]
21
+ relations.map do |relation|
22
+ relation.gateway gateway
23
+ end
24
+ config.register_relation(*relations)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ROM
4
+ module Files
5
+ module Extensions
6
+ module Gem
7
+ module Relations
8
+ class Documentations < ROM::Files::Relation
9
+ dataset { recursive }
10
+
11
+ schema 'text/markdown', as: :documentations, infer: true do
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ROM
4
+ module Files
5
+ module Extensions
6
+ module Gem
7
+ module Relations
8
+ class Executables < ROM::Files::Relation
9
+ dataset { inside('exe') }
10
+
11
+ schema '.', as: :executables, infer: true do
12
+ use :shebang
13
+ use :contents, type: ROM::Files::Types::Ruby::ASTWithComments
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ROM
4
+ module Files
5
+ module Extensions
6
+ module Gem
7
+ module Relations
8
+ class Implementations < ROM::Files::Relation
9
+ dataset { recursive.inside('lib') }
10
+
11
+ schema 'application/x-ruby', as: :implementations, infer: true do
12
+ use :stat
13
+
14
+ attribute :implementation_path, Types::Path
15
+ attribute :specification_path, Types.ForeignKey(
16
+ :specifications,
17
+ map: ->(path) { path.pathmap('spec/%X_spec.rb') }
18
+ )
19
+
20
+ associations do
21
+ has_one :specification, foreign_key: :specification_path
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ROM
4
+ module Files
5
+ module Extensions
6
+ module Gem
7
+ module Relations
8
+ class Specifications < ROM::Files::Relation
9
+ dataset { select('*_spec.rb').recursive.inside('spec') }
10
+
11
+ schema 'application/x-ruby', as: :specifications, infer: true do
12
+ use :stat
13
+
14
+ attribute :specification_path, Types::Path
15
+ attribute :implementation_path, Types.ForeignKey(
16
+ :implementations,
17
+ map: ->(path) { path.pathmap('%{^spec,}X.rb') }
18
+ )
19
+
20
+ associations do
21
+ has_one :implementation, foreign_key: :implementation_path
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'types'
4
+ require_relative '../markup/attributes_inferrer'
5
+
6
+ module ROM
7
+ module Files
8
+ module Extensions
9
+ module Markdown
10
+ class AttributesInferrer < Markup::AttributesInferrer
11
+ def markup_type
12
+ Types::Markdown::Document
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ Schema::AttributesInferrer.register 'text/markdown', Extensions::Markdown::AttributesInferrer.new.freeze
19
+ end
20
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kramdown'
4
+ require 'rom/files/types'
5
+
6
+ module ROM
7
+ module Files
8
+ module Types
9
+ module Markdown
10
+ KDocument = ::Kramdown::Document
11
+
12
+ Document = Dry::Types::Definition[KDocument].new(KDocument).constructor do |doc|
13
+ doc.is_a?(KDocument) ? doc : KDocument.new(doc)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rom/files/schema/attributes_inferrer'
4
+
5
+ module ROM
6
+ module Files
7
+ module Extensions
8
+ module Markup
9
+ class AttributesInferrer < Schema::AttributesInferrer
10
+ def infer_attributes(schema, gateway)
11
+ super + infer_markup_attributes(schema, gateway)
12
+ end
13
+
14
+ def infer_markup_attributes(schema, _gateway)
15
+ [
16
+ build(markup_type.meta(DATA: true), DATA, schema)
17
+ ]
18
+ end
19
+
20
+ # @return [Dry::Types::Definition]
21
+ def markup_type
22
+ raise NotImplementedError, "#{self.class}#markup_type is not implemented"
23
+ end
24
+
25
+ def columns
26
+ super + [DATA]
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'types'
4
+ require_relative '../markup/attributes_inferrer'
5
+
6
+ module ROM
7
+ module Files
8
+ module Extensions
9
+ module Ruby
10
+ class AttributesInferrer < Markup::AttributesInferrer
11
+ # @return [Dry::Types::Definition]
12
+ def markup_type
13
+ Types::Ruby::ASTWithComments
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ Schema::AttributesInferrer.register 'application/x-ruby', Extensions::Ruby::AttributesInferrer.new.freeze
20
+ end
21
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ old_verbose = $VERBOSE
4
+ $VERBOSE = nil
5
+ require 'parser/current'
6
+ $VERBOSE = old_verbose
7
+ require 'rom/files/types'
8
+
9
+ module ROM
10
+ module Files
11
+ module Types
12
+ module Ruby
13
+ ASTNode = Parser::AST::Node
14
+
15
+ AST = ROM::Types.Constructor(ASTNode) do |doc|
16
+ case doc
17
+ when ASTNode
18
+ doc
19
+ when String
20
+ Parser::CurrentRuby.parse(doc)
21
+ when Pathname
22
+ Parser::CurrentRuby.parse(doc.read)
23
+ else
24
+ raise ArgumentError, "Cannot convert #{doc.inspect} to Ruby AST"
25
+ end
26
+ end
27
+
28
+ Comments = Types::Array.of(Parser::Source::Comment)
29
+
30
+ ASTWithComments = ROM::Types.Constructor(Array) do |doc|
31
+ case doc
32
+ when Array
33
+ doc
34
+ when String
35
+ Parser::CurrentRuby.parse_with_comments(doc)
36
+ when Pathname
37
+ Parser::CurrentRuby.parse_file_with_comments(doc.to_s)
38
+ else
39
+ raise ArgumentError, "Cannot convert #{doc.inspect} to Ruby AST"
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end