dase 3.2.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,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .idea
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dase.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Vladimir Yartsev
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # Dase
2
+
3
+ The gem is named by the german mathematician [Johann Dase](http://en.wikipedia.org/wiki/Zacharias_Dase),
4
+ who was a mental calculator - he could count and multiply numbers very quickly. Dase gem adds extra speed
5
+ to Active Record whenever you need to calculate the number of associated records.
6
+
7
+ Here's an example of the code that will cause N + 1 queries:
8
+
9
+ ```
10
+ Author.find_each do |author|
11
+ cnt = author.books.where(year: 1992).count
12
+ puts "#{author.name} has published #{cnt} books in 1992"
13
+ end
14
+ ```
15
+
16
+ Active Record has a built-in solution for efficient fetching of
17
+ associated records - see [Rails Guides](http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations)
18
+ ```
19
+ authors = Author.includes(:books) # => will cause only 2 queries
20
+ authors.first
21
+ ```
22
+
23
+ The Dase gem provides a similar solution for the efficient counting of associated records:
24
+ ```
25
+ authors = Author.includes_count_of(:books) # => will cause only 2 queries
26
+ authors.first.books_count
27
+ ```
28
+
29
+
30
+ ## Installation
31
+
32
+ Add this line to your application's Gemfile:
33
+
34
+ gem 'dase', "~> 3.2.0"
35
+
36
+ And then execute:
37
+
38
+ $ bundle
39
+
40
+ Or install it yourself as:
41
+
42
+ $ gem install dase
43
+
44
+ ### Note on version numbers
45
+
46
+ Dase version number correlates with the Active Record's versions number,
47
+ which it has been tested with.
48
+ E.g. the latest 3.2.* version of Dase will play nicely with the latest 3.2.* version of Active Record.
49
+ Since it's a sort of a "hack", make sure you specified the version number for "dase" gem in your Gemfile.
50
+
51
+ ## Usage
52
+
53
+ ### Basic usage:
54
+
55
+ ```
56
+ Author.includes_count_of(:books).find_each do |author|
57
+ puts "#{author.name} has #{author.books_count} books published"
58
+ end
59
+ ```
60
+
61
+ ### Advanced usage:
62
+
63
+ You can specify a hash of options which will be passed to the underlying finder
64
+ which retrieves the association. Valid keys are: :conditions, :group, :having, :joins, :include
65
+ ```
66
+ Author.includes_count_of(:books, :conditions => {:year => 1990})
67
+ ```
68
+
69
+ ### Known problems
70
+
71
+ 1. Dase doesn't support :through option on associations
72
+ 2. You can't put includes_count_of calls into a scope declaration, like this:
73
+
74
+ ```
75
+ class Author
76
+ scope :with_counters, lambda {
77
+ includes_count_of(:books) # this will not work!!!
78
+ }
79
+ end
80
+ ```
81
+
82
+ ## How it works
83
+
84
+ The equivalent code would look something like this:
85
+ ```
86
+ counters_hash = Book.count(:group => :author_id)
87
+ Author.find_each do |author|
88
+ puts "#{author.name} has #{counters_hash[author.id] || 0} books published"
89
+ end
90
+ ```
91
+
92
+ ## Contributing
93
+
94
+ 1. Fork it
95
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
96
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
97
+ 4. Push to the branch (`git push origin my-new-feature`)
98
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'bundler'
2
+ require 'rspec/core/rake_task'
3
+ require 'rake/testtask'
4
+
5
+ Bundler::GemHelper.install_tasks
6
+
7
+ Rake::TestTask.new(:test) do |test|
8
+ test.libs << 'test'
9
+ end
10
+
11
+ task :default => :test
data/dase.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'dase/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "dase"
8
+ gem.version = Dase::VERSION
9
+ gem.authors = ["Vladimir Yartsev"]
10
+ gem.email = ["vovayartsev@gmail.com"]
11
+ gem.description = %q{A solution for N+1 querying problem in Active Record associated records counting}
12
+ gem.summary = %q{Really fast associated records counting}
13
+ gem.homepage = "https://github.com/vovayartsev"
14
+
15
+ gem.add_runtime_dependency "activerecord", "~> 3.2.0"
16
+ gem.add_runtime_dependency "activesupport", "~> 3.2.0"
17
+ gem.add_development_dependency 'shoulda'
18
+ gem.add_development_dependency 'sqlite3', '~> 1.3.3'
19
+ gem.add_development_dependency 'debugger'
20
+
21
+ gem.files = `git ls-files`.split($/)
22
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
23
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
24
+ gem.require_paths = ["lib"]
25
+ end
@@ -0,0 +1,38 @@
1
+ # Monkey-patching ActiveRecord::Base to add xxx_count methods to it
2
+
3
+ module Dase
4
+ module ARBaseInstanceMethods
5
+ def set_dase_counter(name, value)
6
+ @dase_counters ||= {}
7
+ @dase_counters[name] = value
8
+ end
9
+
10
+ def get_dase_counter(name)
11
+ @dase_counters[name]
12
+ end
13
+
14
+ def respond_to?(*args)
15
+ @dase_counters && @dase_counters.has_key?(args.first.to_sym) || super
16
+ end
17
+
18
+ def method_missing(name, *args)
19
+ if @dase_counters and @dase_counters.has_key?(name.to_sym)
20
+ get_dase_counter(name, *args)
21
+ else
22
+ super
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def self.included(klass)
29
+ class << klass
30
+ delegate :includes_count_of, :to => :scoped
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ ActiveRecord::Base.class_eval do
37
+ include Dase::ARBaseInstanceMethods
38
+ end
@@ -0,0 +1,40 @@
1
+ module Dase
2
+ module ARRelationInstanceMethods
3
+ attr_accessor :dase_values
4
+
5
+ def includes_count_of(*args)
6
+ args.reject! { |a| a.blank? }
7
+ options = args.extract_options!
8
+ options.assert_valid_keys(:conditions, :group, :having, :limit, :offset, :joins, :include, :from, :lock)
9
+ return self if args.empty?
10
+ relation = clone
11
+ relation.dase_values ||= {}
12
+ args.each { |a| relation.dase_values[a] = options}
13
+ relation
14
+ end
15
+
16
+ def attach_dase_counters_to_records
17
+ if dase_values.present? and !@has_dase_counters
18
+ dase_values.each do |associations, options|
19
+ Dase::Preloader.new(@records, associations, options).run
20
+ end
21
+ @has_dase_counters = true
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+
28
+ ActiveRecord::Relation.class_eval do
29
+ include Dase::ARRelationInstanceMethods
30
+
31
+ private
32
+
33
+ alias_method :exec_queries_before_dase, :exec_queries
34
+
35
+ def exec_queries
36
+ exec_queries_before_dase # original method from ActiveRecord
37
+ attach_dase_counters_to_records
38
+ @records
39
+ end
40
+ end
@@ -0,0 +1,35 @@
1
+ module Dase
2
+ class Preloader < ::ActiveRecord::Associations::Preloader
3
+
4
+ # custom preloaders for different association types
5
+ class HasMany < ::ActiveRecord::Associations::Preloader::HasMany
6
+ include Dase::PreloaderMethods
7
+ end
8
+ class HasAndBelongsToMany < ::ActiveRecord::Associations::Preloader::HasAndBelongsToMany
9
+ include Dase::PreloaderMethods
10
+ end
11
+
12
+ # Not implemented yet
13
+ #class HasManyThrough < ::ActiveRecord::Associations::Preloader::HasManyThrough
14
+ # include Dase::PreloaderMethods
15
+ #end
16
+
17
+ # an overloaded version of ActiveRecord::Associations::Preloader's preloader_for
18
+ # which returns a class of a custom preloader for a given association
19
+ def preloader_for(reflection)
20
+ case reflection.macro
21
+ when :has_many
22
+ if reflection.options[:through]
23
+ raise NotImplementedError, "The support for HasManyThrough associations is not implemented yet"
24
+ else
25
+ HasMany
26
+ end
27
+ when :has_one, :belongs_to
28
+ raise ArgumentError, "You can't use includes_count_of with a #{reflection.macro} association"
29
+ when :has_and_belongs_to_many
30
+ HasAndBelongsToMany
31
+ end
32
+ end
33
+ end
34
+
35
+ end
@@ -0,0 +1,15 @@
1
+ module Dase
2
+ module PreloaderMethods
3
+ def preload
4
+ counter_name = "#{reflection.name}_count".to_sym
5
+ pk = model.primary_key.to_sym
6
+ ids = owners.map(&pk)
7
+ fk = "#{scoped.quoted_table_name}.#{reflection.foreign_key}"
8
+ counters_hash = records_for(ids).count(group: fk)
9
+ owners.each do |owner|
10
+ value = counters_hash[owner[pk]] || 0 # 0 is "default count", when no records found
11
+ owner.set_dase_counter(counter_name, value)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ module Dase
2
+ VERSION = "3.2.1"
3
+ end
data/lib/dase.rb ADDED
@@ -0,0 +1,10 @@
1
+ require "dase/version"
2
+ require "dase/preloader_methods"
3
+ require "dase/preloader"
4
+ require "dase/mp_active_record_base"
5
+ require "dase/mp_active_record_relation"
6
+
7
+ module Dase
8
+ # take a look at mp_active_record_* files
9
+ # (there we monkey-patch Active Record)
10
+ end
@@ -0,0 +1,9 @@
1
+ class Author < ActiveRecord::Base
2
+ attr_accessible :name
3
+
4
+ has_many :books
5
+ has_many :old_books, :class_name => "Book", :conditions => {:year => 1990}
6
+
7
+ has_many :quotes, :through => :books
8
+
9
+ end
@@ -0,0 +1,20 @@
1
+ joe:
2
+ name : Joe
3
+ id : 1
4
+ created_at: 1999-02-19 08:00
5
+ updated_at: 1999-02-19 08:00
6
+ # has 3 books: two old (year 1990) and one new (year 2012) book
7
+
8
+ bobby:
9
+ name : Bobby
10
+ id : 2
11
+ created_at: 1999-02-19 08:00
12
+ updated_at: 1999-02-19 08:00
13
+ # has 1 old book (year 1990)
14
+
15
+ teddy:
16
+ name : Teddy
17
+ id : 3
18
+ created_at: 1999-02-19 08:00
19
+ updated_at: 1999-02-19 08:00
20
+ # has no books at all
@@ -0,0 +1,7 @@
1
+ class Book < ActiveRecord::Base
2
+ attr_accessible :title, :year
3
+
4
+ belongs_to :author
5
+ has_many :quotes
6
+
7
+ end
@@ -0,0 +1,34 @@
1
+ # Joe's books
2
+ first:
3
+ id : 1
4
+ year : 1990
5
+ title : First book
6
+ author_id : 1
7
+ created_at: 1999-02-19 08:00
8
+ updated_at: 1999-02-19 08:00
9
+
10
+ second:
11
+ id : 2
12
+ year : 1990
13
+ title : Second book
14
+ author_id : 1
15
+ created_at: 1999-02-19 08:00
16
+ updated_at: 1999-02-19 08:00
17
+
18
+ third:
19
+ id : 3
20
+ year : 2012
21
+ title : Third book
22
+ author_id : 1
23
+ created_at: 1999-02-19 08:00
24
+ updated_at: 1999-02-19 08:00
25
+
26
+
27
+ # Bobby's book
28
+ fourth:
29
+ id : 4
30
+ year : 1990
31
+ title : Fourth book
32
+ author_id : 2
33
+ created_at: 1999-02-19 08:00
34
+ updated_at: 1999-02-19 08:00
@@ -0,0 +1,4 @@
1
+ class Quote < ActiveRecord::Base
2
+ belongs_to :book
3
+
4
+ end
@@ -0,0 +1,16 @@
1
+ # Joe's quotation
2
+ first:
3
+ id: 1
4
+ book_id: 1
5
+ snippet: "To be or not to be, that is the question"
6
+
7
+ # Bobby's quotations
8
+ second:
9
+ id: 2
10
+ book_id: 4
11
+ snippet: "No matter how much cats fight, there always seem to be plenty of kittens"
12
+
13
+ third:
14
+ id: 3
15
+ book_id: 4
16
+ snippet: "I am fond of pigs. Dogs look up to us. Cats look down on us. Pigs treat us as equals."
@@ -0,0 +1,22 @@
1
+ ActiveRecord::Schema.define do
2
+
3
+ create_table "authors", :force => true do |t|
4
+ t.string "name"
5
+ t.datetime "created_at", :null => false
6
+ t.datetime "updated_at", :null => false
7
+ end
8
+
9
+ create_table "books", :force => true do |t|
10
+ t.integer "year"
11
+ t.string "title"
12
+ t.integer "author_id"
13
+ t.datetime "created_at", :null => false
14
+ t.datetime "updated_at", :null => false
15
+ end
16
+
17
+ create_table "quotes", :force => true do |t|
18
+ t.string "snippet"
19
+ t.integer "book_id"
20
+ end
21
+
22
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,30 @@
1
+ # borrowed from https://github.com/ernie/meta_where/blob/master/test/helper.rb
2
+ # with slight modifications
3
+ require "rubygems"
4
+ require "bundler"
5
+ Bundler.setup
6
+ require 'test/unit'
7
+ require 'shoulda'
8
+ require 'active_record'
9
+ require 'active_record/fixtures'
10
+ require 'dase'
11
+
12
+ FIXTURES_PATH = File.join(File.dirname(__FILE__), 'fixtures')
13
+
14
+ ActiveRecord::Base.establish_connection(
15
+ :adapter => defined?(JRUBY_VERSION) ? 'jdbcsqlite3' : 'sqlite3',
16
+ :database => ':memory:'
17
+ )
18
+
19
+ dep = defined?(ActiveSupport::Dependencies) ? ActiveSupport::Dependencies : ::Dependencies
20
+ dep.autoload_paths.unshift FIXTURES_PATH
21
+
22
+ ActiveRecord::Base.silence do
23
+ ActiveRecord::Migration.verbose = false
24
+ load File.join(FIXTURES_PATH, 'schema.rb')
25
+ end
26
+
27
+ ActiveRecord::Fixtures.create_fixtures(FIXTURES_PATH, ActiveRecord::Base.connection.tables)
28
+
29
+ class Test::Unit::TestCase
30
+ end
data/test/test_dase.rb ADDED
@@ -0,0 +1,52 @@
1
+ require 'helper'
2
+
3
+ class TestBase < Test::Unit::TestCase
4
+
5
+ def compare_counts(traditional, dase, true_counts)
6
+ assert_equal true_counts, traditional, "traditional counting failed - fixtures not loaded"
7
+ assert_equal true_counts, dase, "dase countings failed"
8
+ end
9
+
10
+ context "includes_count_of" do
11
+ setup do
12
+ @bobby, @joe, @teddy = Author.order(:name).all
13
+ end
14
+
15
+ should "count books" do
16
+ traditional_counts = Author.order(:name).map { |a| a.books.count }
17
+ dase_counts = Author.includes_count_of(:books).order(:name).map { |a| a.books_count }
18
+ # the order is: Bobby, Joe, Teddy - due to order(:name)
19
+ true_counts = [1, 3, 0] # see books.yml
20
+ compare_counts(traditional_counts, dase_counts, true_counts)
21
+ end
22
+
23
+ should "respond_to the counter method" do
24
+ assert_equal true, Author.includes_count_of(:books).first.respond_to?(:books_count), "doesn't respond'"
25
+ end
26
+
27
+ should "count old books" do
28
+ traditional_counts = Author.order(:name).map { |a| a.old_books.count }
29
+ dase_counts = Author.includes_count_of(:old_books).order(:name).map { |a| a.old_books_count }
30
+ # the order is: Bobby, Joe, Teddy - due to order(:name)
31
+ true_counts = [1, 2, 0] # see books.yml
32
+ compare_counts(traditional_counts, dase_counts, true_counts)
33
+ end
34
+
35
+ should "count books for year 1990" do
36
+ traditional_counts = Author.order(:name).map { |a| a.books.where(year: 1990).count }
37
+ dase_counts = Author.includes_count_of(:books, :conditions => {:year => 1990}).order(:name).map { |a| a.books_count }
38
+ # the order is: Bobby, Joe, Teddy - due to order(:name)
39
+ true_counts = [1, 2, 0] # see books.yml
40
+ compare_counts(traditional_counts, dase_counts, true_counts)
41
+ end
42
+
43
+ # Not yet implemented
44
+ #should "count quotations" do
45
+ # traditional_counts = Author.order(:name).map { |a| a.quotes.count }
46
+ # dase_counts = Author.order(:name).includes_count_of(:quotes).map { |a| a.quotes_count }
47
+ # # the order is: Bobby, Joe, Teddy - due to order(:name)
48
+ # true_counts = [2, 1, 0] # see quotes.yml
49
+ # compare_counts(traditional_counts, dase_counts, true_counts)
50
+ #end
51
+ end
52
+ end
metadata ADDED
@@ -0,0 +1,131 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dase
3
+ version: !ruby/object:Gem::Version
4
+ version: 3.2.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Vladimir Yartsev
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: &70291652811140 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 3.2.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70291652811140
25
+ - !ruby/object:Gem::Dependency
26
+ name: activesupport
27
+ requirement: &70291652810620 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 3.2.0
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70291652810620
36
+ - !ruby/object:Gem::Dependency
37
+ name: shoulda
38
+ requirement: &70291652810220 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70291652810220
47
+ - !ruby/object:Gem::Dependency
48
+ name: sqlite3
49
+ requirement: &70291652808960 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.3.3
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70291652808960
58
+ - !ruby/object:Gem::Dependency
59
+ name: debugger
60
+ requirement: &70291652808360 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70291652808360
69
+ description: A solution for N+1 querying problem in Active Record associated records
70
+ counting
71
+ email:
72
+ - vovayartsev@gmail.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - .gitignore
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - dase.gemspec
83
+ - lib/dase.rb
84
+ - lib/dase/mp_active_record_base.rb
85
+ - lib/dase/mp_active_record_relation.rb
86
+ - lib/dase/preloader.rb
87
+ - lib/dase/preloader_methods.rb
88
+ - lib/dase/version.rb
89
+ - test/fixtures/author.rb
90
+ - test/fixtures/authors.yml
91
+ - test/fixtures/book.rb
92
+ - test/fixtures/books.yml
93
+ - test/fixtures/quote.rb
94
+ - test/fixtures/quotes.yml
95
+ - test/fixtures/schema.rb
96
+ - test/helper.rb
97
+ - test/test_dase.rb
98
+ homepage: https://github.com/vovayartsev
99
+ licenses: []
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ none: false
112
+ requirements:
113
+ - - ! '>='
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ requirements: []
117
+ rubyforge_project:
118
+ rubygems_version: 1.8.11
119
+ signing_key:
120
+ specification_version: 3
121
+ summary: Really fast associated records counting
122
+ test_files:
123
+ - test/fixtures/author.rb
124
+ - test/fixtures/authors.yml
125
+ - test/fixtures/book.rb
126
+ - test/fixtures/books.yml
127
+ - test/fixtures/quote.rb
128
+ - test/fixtures/quotes.yml
129
+ - test/fixtures/schema.rb
130
+ - test/helper.rb
131
+ - test/test_dase.rb