arspy 0.0.1

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.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ .DS_Store
2
+ pkg
3
+ nbproject
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2006-2009 Jeff Patmon
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
File without changes
data/Rakefile ADDED
@@ -0,0 +1,101 @@
1
+ #require 'rake/testtask'
2
+ require 'rake/rdoctask'
3
+ require 'rake/gempackagetask'
4
+ require 'gem_versions'
5
+ #require 'rake/contrib/sshpublisher'
6
+
7
+ spec = Gem::Specification.new do |s|
8
+ s.name = 'arspy'
9
+ s.version = GemVersions.get_version
10
+ s.platform = Gem::Platform::RUBY
11
+ s.description = 'Active Record Spy'
12
+ s.summary = 'Rails console command line tool for browsing and inspecting the structure, associations and data of an ActiveRecord data model.'
13
+
14
+ exclude_folders = '' # 'spec/rails/{doc,lib,log,nbproject,tmp,vendor,test}'
15
+ exclude_files = [] # FileList['**/*.log'] + FileList[exclude_folders+'/**/*'] + FileList[exclude_folders]
16
+ s.files = FileList['{lib,spec}/**/*'] + %w(init.rb LICENSE Rakefile README.rdoc .gitignore) - exclude_files
17
+ s.require_path = 'lib'
18
+ s.has_rdoc = true
19
+ s.test_files = Dir['spec/*_spec.rb']
20
+
21
+ s.author = 'Jeff Patmon'
22
+ s.email = 'jpatmon@gmail.com'
23
+ s.homepage = 'http://github.com/jeffp/arspy/tree/master'
24
+ end
25
+
26
+ require 'spec/version'
27
+ require 'spec/rake/spectask'
28
+
29
+ desc "Run specs"
30
+ namespace :spec do
31
+ task :default=>:object
32
+ Spec::Rake::SpecTask.new(:object) do |t|
33
+ t.spec_files = FileList['spec/*_spec.rb']
34
+ t.libs << 'lib' << 'spec'
35
+ t.rcov = false
36
+ t.spec_opts = ['--options', 'spec/spec.opts']
37
+ #t.rcov_dir = 'coverage'
38
+ #t.rcov_opts = ['--exclude', "kernel,load-diff-lcs\.rb,instance_exec\.rb,lib/spec.rb,lib/spec/runner.rb,^spec/*,bin/spec,examples,/gems,/Library/Ruby,\.autotest,#{ENV['GEM_HOME']}"]
39
+ end
40
+ =begin
41
+ Spec::Rake::SpecTask.new(:sub) do |t|
42
+ t.spec_files = FileList['spec/inheritance_spec.rb']
43
+ t.libs << 'lib' << 'spec'
44
+ t.rcov = false
45
+ t.spec_opts = ['--options', 'spec/spec.opts']
46
+ end
47
+ Spec::Rake::SpecTask.new(:poro) do |t|
48
+ t.spec_files = FileList['spec/poro_spec.rb']
49
+ t.libs << 'lib' << 'spec'
50
+ t.rcov = false
51
+ t.spec_opts = ['--options', 'spec/spec.opts']
52
+ end
53
+
54
+ desc "Run ActiveRecord integration specs"
55
+ Spec::Rake::SpecTask.new(:active_record) do |t|
56
+ t.spec_files = FileList['spec/active_record/*_spec.rb']
57
+ t.libs << 'lib' << 'spec/active_record'
58
+ t.spec_opts = ['--options', 'spec/spec.opts']
59
+ t.rcov = false
60
+ end
61
+ Spec::Rake::SpecTask.new(:forms) do |t|
62
+ t.spec_files = FileList['spec/rails/spec/integrations/*_spec.rb']
63
+ t.libs << 'lib' << 'spec/rails/spec'
64
+ t.spec_opts = ['--options', 'spec/spec.opts']
65
+ t.rcov = false
66
+ end
67
+ # Spec::Rake::SpecTask.new(:associations) do |t|
68
+ # t.spec_files = FileList['spec/active_record/associations_spec.rb']
69
+ # t.libs << 'lib' << 'spec/active_record'
70
+ # t.rcov = false
71
+ # end
72
+ desc "Run all specs"
73
+ task :all=>[:object, :active_record, :forms]
74
+ =end
75
+ end
76
+
77
+
78
+ desc "Generate documentation for the #{spec.name} gem."
79
+ Rake::RDocTask.new(:rdoc) do |rdoc|
80
+ rdoc.rdoc_dir = 'rdoc'
81
+ rdoc.title = spec.name
82
+ #rdoc.template = '../rdoc_template.rb'
83
+ rdoc.options << '--line-numbers' << '--inline-source'
84
+ rdoc.rdoc_files.include('README.rdoc', 'LICENSE', 'lib/**/*.rb')
85
+ end
86
+
87
+ desc 'Generate a gemspec file.'
88
+ task :gemspec do
89
+ File.open("#{spec.name}.gemspec", 'w') do |f|
90
+ f.write spec.to_ruby
91
+ end
92
+ GemVersions.increment_version
93
+ end
94
+
95
+ Rake::GemPackageTask.new(spec) do |p|
96
+ p.gem_spec = spec
97
+ p.need_tar = RUBY_PLATFORM =~ /mswin/ ? false : true
98
+ p.need_zip = true
99
+ end
100
+
101
+ Dir['tasks/**/*.rake'].each {|rake| load rake}
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'arspy'
@@ -0,0 +1,10 @@
1
+ module Arspy
2
+ module ClassExtensions
3
+ module ActiveRecord
4
+ module Base
5
+ def la; Arspy::Operators.la(self); end
6
+ def lf; Arspy::Operators.lf(self); end
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ module Arspy
2
+ module Delegators
3
+ module ActiveRecordExtensions
4
+ def pr(*args); Arspy::Operators.print_object(self, *args); end
5
+ def la; Arspy::Operators.la(self.class); end
6
+ def lf; Arspy::Operators.lf(self.class); end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,33 @@
1
+ module Arspy
2
+ module Delegators
3
+ module ArrayExtensions
4
+ def self.included(base)
5
+ base.define_chained_method(:method_missing, :arspy) do |symbol, *args|
6
+ result = Arspy::Operators.interpret(self, symbol, *args)
7
+ result = method_missing_without_arspy(symbol, *args) unless result
8
+ result
9
+ end
10
+ base.define_chained_method(:id, :arspy) do
11
+ return id_without_arspy if (self.empty? || !self.first.is_a?(ActiveRecord::Base))
12
+ self.map(&:id)
13
+ end
14
+ end
15
+
16
+ def la
17
+ Arspy::Operators.la(self.first.class) unless (self.emtpy? || !(self.first.is_a?(ActiveRecord::Base)))
18
+ end
19
+ def lf
20
+ Arspy::Operators.lf(self.first.class) unless (self.empty? || !(self.first.is_a?(ActiveRecord::Base)))
21
+ end
22
+ def pr(*args)
23
+ Arspy::Operators.print_array(self, *args)
24
+ end
25
+ def wi(*args)
26
+ Arspy::Operators.with(self, *args)
27
+ end
28
+ def wo(*args)
29
+ Arspy::Operators.without(self, *args)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,34 @@
1
+ module Arspy
2
+ module Delegators
3
+ module AssociationCollectionExtensions
4
+ def self.included(base)
5
+ base.define_chained_method(:method_missing, :arspy) do |symbol, *args|
6
+ load_target unless loaded?
7
+ result = Arspy::Operators.interpret(@target, symbol, *args)
8
+ result = method_missing_without_arspy(symbol, *args) unless result
9
+ result
10
+ end
11
+ end
12
+ def pr(*args)
13
+ load_target unless loaded?
14
+ Arspy::Operators.print_array(@target, *args)
15
+ end
16
+ def la
17
+ load_target unless loaded?
18
+ Arspy::Operators.la(@target.first.class) unless (@target.emtpy? || !(@target.first.is_a?(ActiveRecord::Base)))
19
+ end
20
+ def lf
21
+ load_target unless loaded?
22
+ Arspy::Operators.lf(@target.first.class) unless (@target.empty? || !(@target.first.is_a?(ActiveRecord::Base)))
23
+ end
24
+ def wi(*args)
25
+ load_target unless loaded?
26
+ Arspy::Operators.with(@target, *args)
27
+ end
28
+ def wo(*args)
29
+ load_target unless loaded?
30
+ Arspy::Operators.without(@target, *args)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,21 @@
1
+ require 'arspy/delegators/null_extensions'
2
+ require 'arspy/delegators/array_extensions'
3
+ require 'arspy/delegators/association_collection_extensions'
4
+ require 'arspy/delegators/active_record_extensions'
5
+
6
+ module Arspy
7
+ module Delegators
8
+ module Factory
9
+ def self.module_for(klass)
10
+ case klass.name
11
+ when 'Array' then Arspy::Delegators::ArrayExtensions
12
+ when 'ActiveRecord::Base' then Arspy::Delegators::ActiveRecordExtensions
13
+ when 'ActiveRecord::Associations::HasManyThroughAssociation', 'ActiveRecord::Associations::AssociationCollection'
14
+ then Arspy::Delegators::AssociationCollectionExtensions
15
+ else
16
+ Arspy::Delegators::NullExtensions
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,9 @@
1
+ module Arspy
2
+ module Delegators
3
+ module NullExtensions
4
+ def la; end
5
+ def lf; end
6
+ def pr(*args); end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ require 'arspy/delegators/factory'
2
+
3
+ module Arspy
4
+ module Delegators
5
+ end
6
+ end
@@ -0,0 +1,129 @@
1
+ module Arspy
2
+ module Operators
3
+ def self.la(active_record_klass)
4
+ counts = {}
5
+ rows = active_record_klass.reflect_on_all_associations.map do |a|
6
+ counts[a.macro] ||= 0
7
+ counts[a.macro] += 1
8
+ self.format_column_association(a)
9
+ end
10
+ rows.sort!{|a,b| a.first <=> b.first}
11
+ self.print_matrix(rows)
12
+ "Total: #{counts.inject(0){|sum, c| sum+c.last}} (" + counts.map{|c| "#{c.last} #{c.first}" }.join(', ') + ")"
13
+ end
14
+
15
+ def self.lf(active_record_klass)
16
+ rows = active_record_klass.columns.map do |c|
17
+ self.format_column_field(c)
18
+ end
19
+ rows.sort!{|a,b| a.first <=> b.first}
20
+ self.print_matrix(rows)
21
+ "Total #{active_record_klass.columns.size} field#{active_record_klass.columns.size == 1 ? '' : 's'}"
22
+ end
23
+
24
+ def self.format_column_association(a)
25
+ select_options = a.options.select{|k,v| [:through, :as, :polymorphic].include?(k)}
26
+ [a.name.to_s, a.macro.to_s, "(#{a.options[:class_name] || a.name.to_s.singularize.camelize})", select_options.empty? ? '' : Hash[*select_options.flatten].inspect]
27
+ end
28
+ def self.format_column_field(f)
29
+ [f.name.to_s, ":#{f.type}", "(#{f.sql_type})"]
30
+ end
31
+
32
+ def self.print_array(array, *args)
33
+ array.each{|element| puts element.is_a?(String) ? element : element.inspect } if args.empty?
34
+ self.print_matrix(
35
+ array.map do |obj|
36
+ args.map do |arg|
37
+ case arg
38
+ when Symbol then obj.__send__(arg)
39
+ when String then obj.respond_to?(arg) ? obj.__send__(arg) : (obj.instance_eval(arg) rescue nil)
40
+ else nil
41
+ end
42
+ end
43
+ end
44
+ ) unless args.empty?
45
+ nil
46
+ end
47
+
48
+ def self.print_object(object, *args)
49
+ print_matrix([args.map{|a| object[a]}]) if args
50
+ puts(object.inspect) unless args
51
+ nil
52
+ end
53
+ def self.test_object(obj, args)
54
+ args.any? do |arg|
55
+ case arg
56
+ when String then obj.instance_eval(arg) rescue false
57
+ when Integer then obj.id == arg
58
+ when Hash
59
+ arg.any?{|k,v| self.test_attribute(obj, k, (v.is_a?(Array) ? v : [v]) ) }
60
+ else
61
+ false
62
+ end
63
+ end
64
+ end
65
+ def self.with(array, *args)
66
+ return array if (args.empty? || array.nil? || array.empty?)
67
+ array.select{|o| o && self.test_object(o, args)}
68
+ end
69
+ def self.without(array, *args)
70
+ return array if (args.empty? || array.nil? || array.empty?)
71
+ array.select{|o| o && !self.test_object(o, args)}
72
+ end
73
+ def self.interpret(array, symbol, *args)
74
+ return nil unless (array && symbol)
75
+ return nil unless (array.is_a?(Array) && !array.empty? && array.first.is_a?(ActiveRecord::Base))
76
+
77
+ if array.first.class.reflect_on_all_associations.detect{|a| a.name == symbol}
78
+ array.map(&symbol).flatten
79
+ elsif (array.first.attribute_names.include?(symbol.to_s) || array.first.respond_to?(symbol))
80
+ return array.map(&symbol) if args.empty?
81
+ raise 'Hash not allowed as attribute conditionals' if args.any?{|a| a.is_a?(Hash)}
82
+ array.select{|o| o && self.test_attribute(o, symbol, args)}
83
+ else
84
+ nil
85
+ end
86
+ end
87
+
88
+ def self.test_attribute(obj, attr_sym, args)
89
+ return false if (obj.nil? || attr_sym.nil? || args.empty?)
90
+ value = obj.__send__(attr_sym)
91
+ args.any? do |arg|
92
+ case arg
93
+ when String then (arg == value || (obj.instance_eval("#{attr_sym} #{arg}") rescue false))
94
+ when Regexp then arg.match(value)
95
+ when Range then arg.include?(value)
96
+ when Integer then (value.is_a?(ActiveRecord::Base) ? arg == value.id : arg == value) #TODO: what about value is association collection
97
+ when Float then arg == value
98
+ else
99
+ false
100
+ end
101
+ end
102
+ end
103
+
104
+ def self.prepare_arguments(symbol, *args)
105
+ return nil if args.empty?
106
+ Hash[*args.map{|a| a.is_a?(Hash) ? a.map{|k,v| [k, v]} : [symbol, a]}.flatten]
107
+ end
108
+
109
+ @@column_padding = 2
110
+ def self.print_matrix(matrix_array)
111
+ return nil if matrix_array.empty?
112
+ raise 'Cannot print a non-matrix array' unless matrix_array.all?{|ar| ar.is_a? Array }
113
+
114
+ columns_per_row = matrix_array.map{|ar| ar.size }.max
115
+ init_array = Array.new(columns_per_row, 0)
116
+ max_widths = matrix_array.inject(init_array)do |mw, row|
117
+ row.each_with_index do |string, index|
118
+ mw[index] = [string.to_s.length, mw[index]].max
119
+ end
120
+ mw
121
+ end
122
+ matrix_array.each do |row|
123
+ index = -1
124
+ puts (row.map{|column| column.to_s + ' '*(max_widths[index += 1] - column.to_s.length) }.join(' '*@@column_padding))
125
+ end
126
+ nil
127
+ end
128
+ end
129
+ end
data/lib/arspy.rb ADDED
@@ -0,0 +1,26 @@
1
+ raise 'Arspy only runs in an ActiveRecord environment' unless defined?(ActiveRecord::Base)
2
+ $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__))
3
+
4
+ require 'active_support/core_ext/string/inflections'
5
+ require 'meta_programming'
6
+ require 'arspy/operators'
7
+ require 'arspy/delegators'
8
+ require 'arspy/class_extensions'
9
+
10
+ module Arspy
11
+ def self.included(base)
12
+ base.send :include, Delegators::Factory.module_for(base)
13
+ extension = "Arspy::ClassExtensions::#{base.name}".constantize rescue nil
14
+ base.extend(extension) if extension
15
+ end
16
+ end
17
+
18
+ a = ActiveRecord::Associations
19
+ returning([Array, ActiveRecord::Base, a::AssociationCollection ]) { |classes|
20
+ unless a::HasManyThroughAssociation.superclass == a::HasManyAssociation
21
+ classes << a::HasManyThroughAssociation
22
+ end
23
+ }.each do |klass|
24
+ klass.send :include, Arspy
25
+ end
26
+
@@ -0,0 +1,33 @@
1
+ module MetaProgramming
2
+ module Object
3
+ def self.included(base)
4
+ raise 'This module may only be included in class Object' unless base.name == 'Object'
5
+ base.extend(ClassExtensions)
6
+ end
7
+
8
+ module ClassExtensions
9
+ def metaclass
10
+ class << self; self; end
11
+ end
12
+ def safe_alias_method_chain(method_name, ext)
13
+ class_eval do
14
+ method_name_with_ext = "#{method_name}_with_#{ext}".to_sym
15
+ if (method_defined?(method_name_with_ext) && !(metaclass.instance_variable_defined?("@#{method_name_with_ext}")))
16
+ if method_defined?(method_name.to_sym)
17
+ alias_method_chain(method_name.to_sym, ext.to_sym)
18
+ else
19
+ alias_method method_name.to_sym, method_name_with_ext
20
+ define_method("#{method_name}_without_#{ext}".to_sym) {|*args| }
21
+ end
22
+ metaclass.instance_variable_set("@#{method_name_with_ext}", true)
23
+ end
24
+ end
25
+ end
26
+
27
+ def define_chained_method(method_name, ext, &block)
28
+ define_method("#{method_name}_with_#{ext}".to_sym, block)
29
+ safe_alias_method_chain(method_name.to_sym, ext)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,7 @@
1
+ require 'meta_programming/object'
2
+
3
+ module MetaProgramming
4
+ end
5
+
6
+ Object.send :include, MetaProgramming::Object
7
+
data/spec/database.rb ADDED
@@ -0,0 +1,63 @@
1
+ require 'rubygems'
2
+
3
+ gem 'activerecord', ENV['AR_VERSION'] ? "=#{ENV['AR_VERSION']}" : '>=2.1.0'
4
+ require 'active_record'
5
+
6
+ ActiveRecord::Base.establish_connection({'adapter' => 'sqlite3', 'database' => ':memory:'})
7
+ ActiveRecord::Base.logger = Logger.new("#{File.dirname(__FILE__)}/active_record.log")
8
+ cx = ActiveRecord::Base.connection
9
+
10
+ cx.create_table(:things, :force=>true) do |t|
11
+
12
+ end
13
+ cx.create_table(:one_manies, :force=>true) do |t|
14
+
15
+ end
16
+ cx.create_table(:many_manies, :force=>true) do |t|
17
+
18
+ end
19
+ cx.create_table(:many_manies_things, :force=>true) do |t|
20
+
21
+ end
22
+ cx.create_table(:manies_one, :force=>true) do |t|
23
+
24
+ end
25
+
26
+ #basic_associations
27
+ connection.create_table(:companies, :force=>true) do |t|
28
+ t.string :name
29
+ t.string :status
30
+ end
31
+ connection.create_table(:contract_workers, :force=>true) do |t|
32
+ t.references :company
33
+ t.references :contractor
34
+ t.string :status
35
+ end
36
+ connection.create_table(:licenses, :force=>true) do |t|
37
+ t.references :company
38
+ t.string :status
39
+ end
40
+ connection.create_table(:contractors, :force=>true) do |t|
41
+ t.string :name
42
+ t.string :status
43
+ end
44
+ connection.create_table(:employees, :force=>true) do |t|
45
+ t.references :company
46
+ t.string :name
47
+ t.string :status
48
+ end
49
+
50
+ #polymorphic_associations
51
+ connection.create_table(:comments, :force=>true) do |t|
52
+ t.references :document, :polymorphic=>true
53
+ t.text :comment
54
+ t.string :status
55
+ end
56
+ connection.create_table(:articles, :force=>true) do |t|
57
+ t.string :name
58
+ t.string :status
59
+ end
60
+ connection.create_table(:images, :force=>true) do |t|
61
+ t.string :name
62
+ t.string :status
63
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: arspy
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Jeff Patmon
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-04-03 00:00:00 -07:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: Active Record Spy
22
+ email: jpatmon@gmail.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - lib/meta_programming/object.rb
31
+ - lib/arspy/class_extensions.rb
32
+ - lib/arspy/delegators/factory.rb
33
+ - lib/arspy/delegators/association_collection_extensions.rb
34
+ - lib/arspy/delegators/array_extensions.rb
35
+ - lib/arspy/delegators/null_extensions.rb
36
+ - lib/arspy/delegators/active_record_extensions.rb
37
+ - lib/arspy/delegators.rb
38
+ - lib/arspy/operators.rb
39
+ - lib/meta_programming.rb
40
+ - lib/arspy.rb
41
+ - spec/database.rb
42
+ - init.rb
43
+ - LICENSE
44
+ - Rakefile
45
+ - README.rdoc
46
+ - .gitignore
47
+ has_rdoc: true
48
+ homepage: http://github.com/jeffp/arspy/tree/master
49
+ licenses: []
50
+
51
+ post_install_message:
52
+ rdoc_options: []
53
+
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ requirements: []
71
+
72
+ rubyforge_project:
73
+ rubygems_version: 1.3.6
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: Rails console command line tool for browsing and inspecting the structure, associations and data of an ActiveRecord data model.
77
+ test_files: []
78
+