UnderpantsGnome-sunspot 0.9.1.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/History.txt +39 -0
- data/LICENSE +18 -0
- data/README.rdoc +154 -0
- data/Rakefile +9 -0
- data/TODO +4 -0
- data/VERSION.yml +4 -0
- data/bin/sunspot-configure-solr +46 -0
- data/bin/sunspot-solr +62 -0
- data/lib/light_config.rb +40 -0
- data/lib/sunspot.rb +470 -0
- data/lib/sunspot/adapters.rb +265 -0
- data/lib/sunspot/composite_setup.rb +186 -0
- data/lib/sunspot/configuration.rb +38 -0
- data/lib/sunspot/data_extractor.rb +47 -0
- data/lib/sunspot/date_facet.rb +36 -0
- data/lib/sunspot/date_facet_row.rb +17 -0
- data/lib/sunspot/dsl.rb +3 -0
- data/lib/sunspot/dsl/field_query.rb +72 -0
- data/lib/sunspot/dsl/fields.rb +86 -0
- data/lib/sunspot/dsl/query.rb +59 -0
- data/lib/sunspot/dsl/query_facet.rb +31 -0
- data/lib/sunspot/dsl/restriction.rb +25 -0
- data/lib/sunspot/dsl/scope.rb +193 -0
- data/lib/sunspot/dsl/search.rb +30 -0
- data/lib/sunspot/facet.rb +51 -0
- data/lib/sunspot/facet_row.rb +34 -0
- data/lib/sunspot/field.rb +157 -0
- data/lib/sunspot/field_factory.rb +126 -0
- data/lib/sunspot/indexer.rb +127 -0
- data/lib/sunspot/instantiated_facet.rb +38 -0
- data/lib/sunspot/instantiated_facet_row.rb +12 -0
- data/lib/sunspot/query.rb +190 -0
- data/lib/sunspot/query/base_query.rb +90 -0
- data/lib/sunspot/query/connective.rb +77 -0
- data/lib/sunspot/query/dynamic_query.rb +69 -0
- data/lib/sunspot/query/field_facet.rb +149 -0
- data/lib/sunspot/query/field_query.rb +57 -0
- data/lib/sunspot/query/pagination.rb +39 -0
- data/lib/sunspot/query/query_facet.rb +72 -0
- data/lib/sunspot/query/query_facet_row.rb +19 -0
- data/lib/sunspot/query/restriction.rb +225 -0
- data/lib/sunspot/query/scope.rb +165 -0
- data/lib/sunspot/query/sort.rb +36 -0
- data/lib/sunspot/query/sort_composite.rb +33 -0
- data/lib/sunspot/query_facet.rb +33 -0
- data/lib/sunspot/query_facet_row.rb +21 -0
- data/lib/sunspot/schema.rb +165 -0
- data/lib/sunspot/search.rb +222 -0
- data/lib/sunspot/search/hit.rb +62 -0
- data/lib/sunspot/session.rb +201 -0
- data/lib/sunspot/setup.rb +271 -0
- data/lib/sunspot/type.rb +200 -0
- data/lib/sunspot/util.rb +164 -0
- data/solr/etc/jetty.xml +212 -0
- data/solr/etc/webdefault.xml +379 -0
- data/solr/lib/jetty-6.1.3.jar +0 -0
- data/solr/lib/jetty-util-6.1.3.jar +0 -0
- data/solr/lib/jsp-2.1/ant-1.6.5.jar +0 -0
- data/solr/lib/jsp-2.1/core-3.1.1.jar +0 -0
- data/solr/lib/jsp-2.1/jsp-2.1.jar +0 -0
- data/solr/lib/jsp-2.1/jsp-api-2.1.jar +0 -0
- data/solr/lib/servlet-api-2.5-6.1.3.jar +0 -0
- data/solr/solr/conf/elevate.xml +36 -0
- data/solr/solr/conf/protwords.txt +21 -0
- data/solr/solr/conf/schema.xml +50 -0
- data/solr/solr/conf/solrconfig.xml +696 -0
- data/solr/solr/conf/stopwords.txt +57 -0
- data/solr/solr/conf/synonyms.txt +31 -0
- data/solr/start.jar +0 -0
- data/solr/webapps/solr.war +0 -0
- data/spec/api/adapters_spec.rb +33 -0
- data/spec/api/build_search_spec.rb +918 -0
- data/spec/api/indexer_spec.rb +311 -0
- data/spec/api/query_spec.rb +153 -0
- data/spec/api/search_retrieval_spec.rb +325 -0
- data/spec/api/session_spec.rb +157 -0
- data/spec/api/spec_helper.rb +1 -0
- data/spec/api/sunspot_spec.rb +18 -0
- data/spec/integration/dynamic_fields_spec.rb +55 -0
- data/spec/integration/faceting_spec.rb +169 -0
- data/spec/integration/keyword_search_spec.rb +83 -0
- data/spec/integration/scoped_search_spec.rb +188 -0
- data/spec/integration/spec_helper.rb +1 -0
- data/spec/integration/stored_fields_spec.rb +10 -0
- data/spec/integration/test_pagination.rb +32 -0
- data/spec/mocks/adapters.rb +32 -0
- data/spec/mocks/blog.rb +3 -0
- data/spec/mocks/comment.rb +19 -0
- data/spec/mocks/connection.rb +84 -0
- data/spec/mocks/mock_adapter.rb +30 -0
- data/spec/mocks/mock_record.rb +41 -0
- data/spec/mocks/photo.rb +8 -0
- data/spec/mocks/post.rb +70 -0
- data/spec/mocks/user.rb +8 -0
- data/spec/spec_helper.rb +47 -0
- data/tasks/gemspec.rake +25 -0
- data/tasks/rcov.rake +28 -0
- data/tasks/rdoc.rake +21 -0
- data/tasks/schema.rake +19 -0
- data/tasks/spec.rake +24 -0
- data/tasks/todo.rake +4 -0
- data/templates/schema.xml.haml +24 -0
- metadata +245 -0
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe 'pagination' do
|
4
|
+
before :all do
|
5
|
+
Sunspot.remove_all
|
6
|
+
@posts = (0..19).map do |i|
|
7
|
+
Post.new(:blog_id => i)
|
8
|
+
end
|
9
|
+
Sunspot.index(*@posts)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should return all by default' do
|
13
|
+
results = Sunspot.search(Post) { order_by :blog_id }.results
|
14
|
+
results.should == @posts
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should return first page of 10' do
|
18
|
+
results = Sunspot.search(Post) do
|
19
|
+
order_by :blog_id
|
20
|
+
paginate :page => 1, :per_page => 10
|
21
|
+
end.results
|
22
|
+
results.should == @posts[0,10]
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should return second page of 10' do
|
26
|
+
results = Sunspot.search(Post) do
|
27
|
+
order_by :blog_id
|
28
|
+
paginate :page => 2, :per_page => 10
|
29
|
+
end.results
|
30
|
+
results.should == @posts[10,10]
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class AbstractModel
|
2
|
+
end
|
3
|
+
|
4
|
+
class Model < AbstractModel
|
5
|
+
end
|
6
|
+
|
7
|
+
class AbstractModelInstanceAdapter < Sunspot::Adapters::InstanceAdapter
|
8
|
+
end
|
9
|
+
|
10
|
+
class AbstractModelDataAccessor < Sunspot::Adapters::DataAccessor
|
11
|
+
end
|
12
|
+
|
13
|
+
Sunspot::Adapters::InstanceAdapter.register(AbstractModelInstanceAdapter, AbstractModel)
|
14
|
+
Sunspot::Adapters::DataAccessor.register(AbstractModelDataAccessor, AbstractModel)
|
15
|
+
|
16
|
+
|
17
|
+
module MixInModel
|
18
|
+
end
|
19
|
+
|
20
|
+
class MixModel
|
21
|
+
include MixInModel
|
22
|
+
end
|
23
|
+
|
24
|
+
class MixInModelInstanceAdapter < Sunspot::Adapters::InstanceAdapter
|
25
|
+
end
|
26
|
+
|
27
|
+
class MixInModelDataAccessor < Sunspot::Adapters::DataAccessor
|
28
|
+
end
|
29
|
+
|
30
|
+
Sunspot::Adapters::InstanceAdapter.register(MixInModelInstanceAdapter, MixInModel)
|
31
|
+
Sunspot::Adapters::DataAccessor.register(MixInModelDataAccessor, MixInModel)
|
32
|
+
|
data/spec/mocks/blog.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Namespaced
|
2
|
+
class Comment < MockRecord
|
3
|
+
attr_reader :id
|
4
|
+
attr_accessor :author_name, :published_at, :body, :average_rating, :boost
|
5
|
+
|
6
|
+
def custom_string
|
7
|
+
@custom_string ||= {}
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
Sunspot.setup(Namespaced::Comment) do
|
13
|
+
text :body, :author_name
|
14
|
+
string :author_name
|
15
|
+
time :published_at
|
16
|
+
integer :average_rating
|
17
|
+
dynamic_string :custom_string
|
18
|
+
boost :boost
|
19
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Mock
|
2
|
+
class ConnectionFactory
|
3
|
+
def new(adapter = nil, opts = nil)
|
4
|
+
if @instance
|
5
|
+
raise('Factory can only create an instance once!')
|
6
|
+
else
|
7
|
+
@instance = Connection.new(adapter, opts)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def instance
|
12
|
+
@instance ||= Connection.new
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Connection
|
17
|
+
attr_reader :adds, :commits, :searches
|
18
|
+
attr_accessor :adapter, :opts
|
19
|
+
|
20
|
+
def initialize(adapter = nil, opts = nil)
|
21
|
+
@adapter, @opts = adapter, opts
|
22
|
+
@adds, @deletes, @deletes_by_query, @commits, @searches = Array.new(5) { [] }
|
23
|
+
end
|
24
|
+
|
25
|
+
def add(documents)
|
26
|
+
@adds << Array(documents)
|
27
|
+
end
|
28
|
+
|
29
|
+
def delete_by_id(*ids)
|
30
|
+
@deletes << ids
|
31
|
+
end
|
32
|
+
|
33
|
+
def delete_by_query(query)
|
34
|
+
@deletes_by_query << query
|
35
|
+
end
|
36
|
+
|
37
|
+
def commit
|
38
|
+
@commits << Time.now
|
39
|
+
end
|
40
|
+
|
41
|
+
def select(params)
|
42
|
+
@searches << @last_search = params
|
43
|
+
end
|
44
|
+
|
45
|
+
def has_add_with?(*documents)
|
46
|
+
@adds.any? do |add|
|
47
|
+
documents.all? do |document|
|
48
|
+
add.any? do |added|
|
49
|
+
if document.is_a?(Hash)
|
50
|
+
document.all? do |field, value|
|
51
|
+
added.fields_by_name(field).map do |field|
|
52
|
+
field.value
|
53
|
+
end == Array(value)
|
54
|
+
end
|
55
|
+
else
|
56
|
+
!added.fields_by_name(document).empty?
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def has_delete?(*ids)
|
64
|
+
@deletes.any? do |delete|
|
65
|
+
delete & ids == ids
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def has_delete_by_query?(query)
|
70
|
+
@deletes_by_query.include?(query)
|
71
|
+
end
|
72
|
+
|
73
|
+
def has_last_search_with?(params)
|
74
|
+
return unless @last_search
|
75
|
+
if params.respond_to?(:all?)
|
76
|
+
params.all? do |key, value|
|
77
|
+
@last_search.has_key?(key) && @last_search[key] == value
|
78
|
+
end
|
79
|
+
else
|
80
|
+
@last_search.has_key?(params)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'post')
|
2
|
+
|
3
|
+
module MockAdapter
|
4
|
+
class InstanceAdapter < Sunspot::Adapters::InstanceAdapter
|
5
|
+
def id
|
6
|
+
@instance.id
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class DataAccessor < Sunspot::Adapters::DataAccessor
|
11
|
+
def load(id)
|
12
|
+
@clazz.get(id.to_i)
|
13
|
+
end
|
14
|
+
|
15
|
+
def load_all(ids)
|
16
|
+
all = @clazz.get_all(ids.map { |id| id.to_i })
|
17
|
+
if @custom_title
|
18
|
+
all.each { |item| item.title = @custom_title }
|
19
|
+
end
|
20
|
+
all
|
21
|
+
end
|
22
|
+
|
23
|
+
def custom_title=(custom_title)
|
24
|
+
@custom_title = custom_title
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
Sunspot::Adapters::DataAccessor.register(MockAdapter::DataAccessor, MockRecord)
|
30
|
+
Sunspot::Adapters::InstanceAdapter.register(MockAdapter::InstanceAdapter, MockRecord)
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class MockRecord
|
2
|
+
IDS = Hash.new { |h, k| h[k] = 0 }
|
3
|
+
QUERY_COUNTS = Hash.new { |h, k| h[k] = 0 }
|
4
|
+
INSTANCES = Hash.new { |h, k| h[k] = {} }
|
5
|
+
|
6
|
+
attr_reader :id
|
7
|
+
|
8
|
+
def initialize(attrs = {})
|
9
|
+
attrs.each_pair do |name, value|
|
10
|
+
send(:"#{name}=", value)
|
11
|
+
end
|
12
|
+
@id = IDS[self.class.name.to_sym] += 1
|
13
|
+
INSTANCES[self.class.name.to_sym][@id] = self
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.inherited(base)
|
17
|
+
base.extend(ClassMethods)
|
18
|
+
end
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
def get(id)
|
22
|
+
QUERY_COUNTS[self.name.to_sym] += 1
|
23
|
+
get_instance(id)
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_all(ids)
|
27
|
+
QUERY_COUNTS[self.name.to_sym] += 1
|
28
|
+
ids.map { |id| get_instance(id) }.sort_by { |instance| instance.id }
|
29
|
+
end
|
30
|
+
|
31
|
+
def query_count
|
32
|
+
QUERY_COUNTS[self.name.to_sym]
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def get_instance(id)
|
38
|
+
INSTANCES[self.name.to_sym][id]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/spec/mocks/photo.rb
ADDED
data/spec/mocks/post.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'blog')
|
2
|
+
|
3
|
+
class Post < MockRecord
|
4
|
+
attr_accessor :title, :body, :blog_id, :published_at, :ratings_average,
|
5
|
+
:author_name, :featured, :expire_date
|
6
|
+
alias_method :featured?, :featured
|
7
|
+
|
8
|
+
def category_ids
|
9
|
+
@category_ids ||= []
|
10
|
+
end
|
11
|
+
|
12
|
+
def custom_string
|
13
|
+
@custom_string ||= {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def custom_fl
|
17
|
+
@custom_fl ||= {}
|
18
|
+
end
|
19
|
+
|
20
|
+
def custom_time
|
21
|
+
@custom_time ||= {}
|
22
|
+
end
|
23
|
+
|
24
|
+
def custom_boolean
|
25
|
+
@custom_boolean ||= {}
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
attr_writer :category_ids, :custom_string, :custom_fl, :custom_time, :custom_boolean
|
30
|
+
end
|
31
|
+
|
32
|
+
Sunspot.setup(Post) do
|
33
|
+
text :title, :boost => 2
|
34
|
+
text :body
|
35
|
+
text :backwards_title do
|
36
|
+
title.reverse if title
|
37
|
+
end
|
38
|
+
string :title, :stored => true
|
39
|
+
integer :blog_id, :references => Blog
|
40
|
+
integer :category_ids, :multiple => true
|
41
|
+
float :average_rating, :using => :ratings_average
|
42
|
+
time :published_at
|
43
|
+
date :expire_date
|
44
|
+
boolean :featured, :using => :featured?
|
45
|
+
string :sort_title do
|
46
|
+
title.downcase.sub(/^(a|an|the)\W+/, '') if title
|
47
|
+
end
|
48
|
+
integer :primary_category_id do |post|
|
49
|
+
post.category_ids.first
|
50
|
+
end
|
51
|
+
time :last_indexed_at, :stored => true do
|
52
|
+
Time.now
|
53
|
+
end
|
54
|
+
|
55
|
+
dynamic_string :custom_string
|
56
|
+
dynamic_float :custom_float, :multiple => true, :using => :custom_fl
|
57
|
+
dynamic_integer :custom_integer do
|
58
|
+
category_ids.inject({}) do |hash, category_id|
|
59
|
+
hash.merge(category_id => 1)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
dynamic_time :custom_time
|
63
|
+
dynamic_boolean :custom_boolean
|
64
|
+
|
65
|
+
boost do
|
66
|
+
if ratings_average
|
67
|
+
1 + (ratings_average - 3.0) / 4.0
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/spec/mocks/user.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
using_gems = false
|
2
|
+
begin
|
3
|
+
require 'spec'
|
4
|
+
begin
|
5
|
+
require 'ruby-debug'
|
6
|
+
rescue LoadError => e
|
7
|
+
if using_gems
|
8
|
+
module Kernel
|
9
|
+
def debugger
|
10
|
+
STDERR.puts('Debugger is not available')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
else
|
14
|
+
raise(e)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
if ENV['USE_WILL_PAGINATE']
|
18
|
+
require 'will_paginate'
|
19
|
+
require 'will_paginate/collection'
|
20
|
+
end
|
21
|
+
rescue LoadError => e
|
22
|
+
require 'rubygems'
|
23
|
+
if using_gems
|
24
|
+
raise(e)
|
25
|
+
else
|
26
|
+
using_gems = true
|
27
|
+
retry
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
unless gem_name = ENV['SUNSPOT_TEST_GEM']
|
32
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
33
|
+
else
|
34
|
+
gem gem_name
|
35
|
+
end
|
36
|
+
require 'sunspot'
|
37
|
+
|
38
|
+
require File.join(File.dirname(__FILE__), 'mocks', 'mock_record.rb')
|
39
|
+
Dir.glob(File.join(File.dirname(__FILE__), 'mocks', '**', '*.rb')).each do |file|
|
40
|
+
require file unless File.basename(file) == 'mock_record.rb'
|
41
|
+
end
|
42
|
+
|
43
|
+
def without_class(clazz)
|
44
|
+
Object.class_eval { remove_const(clazz.name.to_sym) }
|
45
|
+
yield
|
46
|
+
Object.class_eval { const_set(clazz.name.to_sym, clazz) }
|
47
|
+
end
|
data/tasks/gemspec.rake
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
begin
|
2
|
+
gem 'technicalpickles-jeweler', '~> 1.0.1'
|
3
|
+
require 'jeweler'
|
4
|
+
Jeweler::Tasks.new do |s|
|
5
|
+
s.name = 'sunspot'
|
6
|
+
s.executables = 'sunspot-solr'
|
7
|
+
s.summary = 'Library for expressive, powerful interaction with the Solr search engine'
|
8
|
+
s.email = 'mat@patch.com'
|
9
|
+
s.homepage = 'http://github.com/outoftime/sunspot'
|
10
|
+
s.description = 'Library for expressive, powerful interaction with the Solr search engine'
|
11
|
+
s.authors = ['Mat Brown', 'Peer Allan', 'Dmitriy Dzema', 'Benjamin Krause']
|
12
|
+
s.files = FileList['[A-Z]*', '{bin,lib,spec,tasks,templates}/**/*', 'solr/{etc,lib,webapps}/**/*', 'solr/solr/conf/*', 'solr/start.jar']
|
13
|
+
s.add_dependency 'mwmitchell-rsolr', '>= 0.8.9'
|
14
|
+
s.add_dependency 'daemons', '~> 1.0'
|
15
|
+
s.add_dependency 'optiflag', '~> 0.6.5'
|
16
|
+
s.add_dependency 'haml', '~> 2.2'
|
17
|
+
s.add_development_dependency 'rspec', '~> 1.1'
|
18
|
+
s.add_development_dependency 'ruby-debug', '~> 0.10'
|
19
|
+
s.extra_rdoc_files = ['README.rdoc']
|
20
|
+
s.rdoc_options << '--webcvs=http://github.com/outoftime/sunspot/tree/master/%s' <<
|
21
|
+
'--title' << 'Sunspot - Solr-powered search for Ruby objects - API Documentation' <<
|
22
|
+
'--main' << 'README.rdoc'
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
data/tasks/rcov.rake
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'spec/rake/spectask'
|
3
|
+
|
4
|
+
desc 'run specs with rcov'
|
5
|
+
Spec::Rake::SpecTask.new('rcov') do |t|
|
6
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
7
|
+
t.rcov = true
|
8
|
+
t.rcov_dir = File.join('coverage', 'all')
|
9
|
+
t.rcov_opts.concat(['--exclude', 'spec', '--sort', 'coverage', '--only-uncovered'])
|
10
|
+
end
|
11
|
+
|
12
|
+
namespace :rcov do
|
13
|
+
desc 'run api specs with rcov'
|
14
|
+
Spec::Rake::SpecTask.new('api') do |t|
|
15
|
+
t.spec_files = FileList['spec/api/*_spec.rb']
|
16
|
+
t.rcov = true
|
17
|
+
t.rcov_dir = File.join('coverage', 'api')
|
18
|
+
t.rcov_opts.concat(['--exclude', 'spec', '--sort', 'coverage', '--only-uncovered'])
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'run integration specs with rcov'
|
22
|
+
Spec::Rake::SpecTask.new('integration') do |t|
|
23
|
+
t.spec_files = FileList['spec/integration/*_spec.rb']
|
24
|
+
t.rcov = true
|
25
|
+
t.rcov_dir = File.join('coverage', 'integration')
|
26
|
+
t.rcov_opts.concat(['--exclude', 'spec', '--sort', 'coverage', '--only-uncovered'])
|
27
|
+
end
|
28
|
+
end
|