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,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