jmonteiro-mongo_mapper 0.1.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.
- data/.gitignore +10 -0
- data/LICENSE +20 -0
- data/README.rdoc +38 -0
- data/Rakefile +55 -0
- data/VERSION +1 -0
- data/bin/mmconsole +60 -0
- data/jmonteiro-mongo_mapper.gemspec +195 -0
- data/lib/mongo_mapper.rb +128 -0
- data/lib/mongo_mapper/descendant_appends.rb +44 -0
- data/lib/mongo_mapper/document.rb +402 -0
- data/lib/mongo_mapper/dynamic_finder.rb +74 -0
- data/lib/mongo_mapper/embedded_document.rb +61 -0
- data/lib/mongo_mapper/finder_options.rb +127 -0
- data/lib/mongo_mapper/plugins.rb +19 -0
- data/lib/mongo_mapper/plugins/associations.rb +104 -0
- data/lib/mongo_mapper/plugins/associations/base.rb +121 -0
- data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +28 -0
- data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +23 -0
- data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
- data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +49 -0
- data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +139 -0
- data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
- data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +117 -0
- data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
- data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
- data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
- data/lib/mongo_mapper/plugins/associations/one_proxy.rb +66 -0
- data/lib/mongo_mapper/plugins/associations/proxy.rb +118 -0
- data/lib/mongo_mapper/plugins/callbacks.rb +65 -0
- data/lib/mongo_mapper/plugins/clone.rb +13 -0
- data/lib/mongo_mapper/plugins/descendants.rb +16 -0
- data/lib/mongo_mapper/plugins/dirty.rb +119 -0
- data/lib/mongo_mapper/plugins/equality.rb +11 -0
- data/lib/mongo_mapper/plugins/identity_map.rb +66 -0
- data/lib/mongo_mapper/plugins/inspect.rb +14 -0
- data/lib/mongo_mapper/plugins/keys.rb +295 -0
- data/lib/mongo_mapper/plugins/logger.rb +17 -0
- data/lib/mongo_mapper/plugins/pagination.rb +85 -0
- data/lib/mongo_mapper/plugins/protected.rb +31 -0
- data/lib/mongo_mapper/plugins/rails.rb +80 -0
- data/lib/mongo_mapper/plugins/serialization.rb +109 -0
- data/lib/mongo_mapper/plugins/validations.rb +48 -0
- data/lib/mongo_mapper/support.rb +213 -0
- data/performance/read_write.rb +52 -0
- data/specs.watchr +51 -0
- data/test/NOTE_ON_TESTING +1 -0
- data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +63 -0
- data/test/functional/associations/test_belongs_to_proxy.rb +93 -0
- data/test/functional/associations/test_in_array_proxy.rb +309 -0
- data/test/functional/associations/test_many_documents_as_proxy.rb +246 -0
- data/test/functional/associations/test_many_documents_proxy.rb +437 -0
- data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +175 -0
- data/test/functional/associations/test_many_embedded_proxy.rb +216 -0
- data/test/functional/associations/test_many_polymorphic_proxy.rb +340 -0
- data/test/functional/associations/test_one_proxy.rb +149 -0
- data/test/functional/test_associations.rb +44 -0
- data/test/functional/test_binary.rb +27 -0
- data/test/functional/test_callbacks.rb +81 -0
- data/test/functional/test_dirty.rb +156 -0
- data/test/functional/test_document.rb +1171 -0
- data/test/functional/test_embedded_document.rb +125 -0
- data/test/functional/test_identity_map.rb +233 -0
- data/test/functional/test_logger.rb +20 -0
- data/test/functional/test_modifiers.rb +252 -0
- data/test/functional/test_pagination.rb +93 -0
- data/test/functional/test_protected.rb +41 -0
- data/test/functional/test_string_id_compatibility.rb +67 -0
- data/test/functional/test_validations.rb +329 -0
- data/test/models.rb +232 -0
- data/test/support/custom_matchers.rb +55 -0
- data/test/support/timing.rb +16 -0
- data/test/test_helper.rb +60 -0
- data/test/unit/associations/test_base.rb +207 -0
- data/test/unit/associations/test_proxy.rb +103 -0
- data/test/unit/serializers/test_json_serializer.rb +189 -0
- data/test/unit/test_descendant_appends.rb +71 -0
- data/test/unit/test_document.rb +203 -0
- data/test/unit/test_dynamic_finder.rb +125 -0
- data/test/unit/test_embedded_document.rb +628 -0
- data/test/unit/test_finder_options.rb +325 -0
- data/test/unit/test_keys.rb +169 -0
- data/test/unit/test_mongo_mapper.rb +65 -0
- data/test/unit/test_pagination.rb +127 -0
- data/test/unit/test_plugins.rb +42 -0
- data/test/unit/test_rails.rb +139 -0
- data/test/unit/test_rails_compatibility.rb +42 -0
- data/test/unit/test_serialization.rb +51 -0
- data/test/unit/test_support.rb +350 -0
- data/test/unit/test_time_zones.rb +39 -0
- data/test/unit/test_validations.rb +492 -0
- metadata +260 -0
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'active_support/json'
|
2
|
+
|
3
|
+
module MongoMapper
|
4
|
+
module Plugins
|
5
|
+
module Serialization
|
6
|
+
class Serializer
|
7
|
+
attr_reader :options
|
8
|
+
|
9
|
+
def initialize(record, options={})
|
10
|
+
@record, @options = record, options.dup
|
11
|
+
end
|
12
|
+
|
13
|
+
def serializable_key_names
|
14
|
+
key_names = @record.attributes.keys
|
15
|
+
|
16
|
+
if options[:only]
|
17
|
+
options.delete(:except)
|
18
|
+
key_names = key_names & Array(options[:only]).collect { |n| n.to_s }
|
19
|
+
else
|
20
|
+
options[:except] = Array(options[:except])
|
21
|
+
key_names = key_names - options[:except].collect { |n| n.to_s }
|
22
|
+
end
|
23
|
+
|
24
|
+
key_names
|
25
|
+
end
|
26
|
+
|
27
|
+
def serializable_method_names
|
28
|
+
Array(options[:methods]).inject([]) do |method_attributes, name|
|
29
|
+
method_attributes << name if @record.respond_to?(name.to_s)
|
30
|
+
method_attributes
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def serializable_names
|
35
|
+
serializable_key_names + serializable_method_names
|
36
|
+
end
|
37
|
+
|
38
|
+
def serializable_record
|
39
|
+
returning(serializable_record = {}) do
|
40
|
+
serializable_names.each { |name| serializable_record[name] = @record.send(name) }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def serialize
|
45
|
+
# overwrite to implement
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_s(&block)
|
49
|
+
serialize(&block)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
module Json
|
54
|
+
def self.included(base)
|
55
|
+
base.cattr_accessor :include_root_in_json, :instance_writer => false
|
56
|
+
base.extend ClassMethods
|
57
|
+
end
|
58
|
+
|
59
|
+
module ClassMethods
|
60
|
+
def json_class_name
|
61
|
+
@json_class_name ||= name.demodulize.underscore.inspect
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_json(options={})
|
66
|
+
apply_to_json_defaults(options)
|
67
|
+
|
68
|
+
if include_root_in_json
|
69
|
+
"{#{self.class.json_class_name}: #{JsonSerializer.new(self, options).to_s}}"
|
70
|
+
else
|
71
|
+
JsonSerializer.new(self, options).to_s
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def from_json(json)
|
76
|
+
self.attributes = ActiveSupport::JSON.decode(json)
|
77
|
+
self
|
78
|
+
end
|
79
|
+
|
80
|
+
class JsonSerializer < Serializer
|
81
|
+
def serialize
|
82
|
+
serializable_record.to_json
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
def apply_to_json_defaults(options)
|
88
|
+
unless options[:only]
|
89
|
+
methods = [options.delete(:methods)].flatten.compact
|
90
|
+
methods << :id
|
91
|
+
options[:methods] = methods.uniq
|
92
|
+
end
|
93
|
+
|
94
|
+
except = [options.delete(:except)].flatten.compact
|
95
|
+
except << :_id
|
96
|
+
options[:except] = except
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
module InstanceMethods
|
101
|
+
def self.included(model)
|
102
|
+
model.class_eval do
|
103
|
+
include Json
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Plugins
|
3
|
+
module Validations
|
4
|
+
module InstanceMethods
|
5
|
+
def self.included(model)
|
6
|
+
model.class_eval { include Validatable }
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module DocumentMacros
|
11
|
+
def validates_uniqueness_of(*args)
|
12
|
+
add_validations(args, MongoMapper::Plugins::Validations::ValidatesUniquenessOf)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class ValidatesUniquenessOf < Validatable::ValidationBase
|
17
|
+
option :scope, :case_sensitive
|
18
|
+
default :case_sensitive => true
|
19
|
+
|
20
|
+
def valid?(instance)
|
21
|
+
value = instance[attribute]
|
22
|
+
return true if allow_blank && value.blank?
|
23
|
+
return true if allow_nil && value.nil?
|
24
|
+
base_conditions = case_sensitive ? {self.attribute => value} : {}
|
25
|
+
doc = instance.class.first(base_conditions.merge(scope_conditions(instance)).merge(where_conditions(instance)))
|
26
|
+
doc.nil? || instance._id == doc._id
|
27
|
+
end
|
28
|
+
|
29
|
+
def message(instance)
|
30
|
+
super || "has already been taken"
|
31
|
+
end
|
32
|
+
|
33
|
+
def scope_conditions(instance)
|
34
|
+
return {} unless scope
|
35
|
+
Array(scope).inject({}) do |conditions, key|
|
36
|
+
conditions.merge(key => instance[key])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def where_conditions(instance)
|
41
|
+
conditions = {}
|
42
|
+
conditions[attribute] = /#{instance[attribute].to_s}/i unless case_sensitive
|
43
|
+
conditions
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
class Array
|
2
|
+
def self.to_mongo(value)
|
3
|
+
value = value.respond_to?(:lines) ? value.lines : value
|
4
|
+
value.to_a
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.from_mongo(value)
|
8
|
+
value || []
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Binary
|
13
|
+
def self.to_mongo(value)
|
14
|
+
if value.is_a?(ByteBuffer)
|
15
|
+
value
|
16
|
+
else
|
17
|
+
value.nil? ? nil : ByteBuffer.new(value)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.from_mongo(value)
|
22
|
+
value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Boolean
|
27
|
+
BOOLEAN_MAPPING = {
|
28
|
+
true => true, 'true' => true, 'TRUE' => true, 'True' => true, 't' => true, 'T' => true, '1' => true, 1 => true, 1.0 => true,
|
29
|
+
false => false, 'false' => false, 'FALSE' => false, 'False' => false, 'f' => false, 'F' => false, '0' => false, 0 => false, 0.0 => false, nil => false
|
30
|
+
}
|
31
|
+
|
32
|
+
def self.to_mongo(value)
|
33
|
+
if value.is_a?(Boolean)
|
34
|
+
value
|
35
|
+
else
|
36
|
+
v = BOOLEAN_MAPPING[value]
|
37
|
+
v = value.to_s.downcase == 'true' if v.nil? # Check all mixed case spellings for true
|
38
|
+
v
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.from_mongo(value)
|
43
|
+
!!value
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class Date
|
48
|
+
def self.to_mongo(value)
|
49
|
+
if value.nil? || value == ''
|
50
|
+
nil
|
51
|
+
else
|
52
|
+
date = value.is_a?(Date) || value.is_a?(Time) ? value : Date.parse(value.to_s)
|
53
|
+
Time.utc(date.year, date.month, date.day)
|
54
|
+
end
|
55
|
+
rescue
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.from_mongo(value)
|
60
|
+
value.to_date if value.present?
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class Float
|
65
|
+
def self.to_mongo(value)
|
66
|
+
value.to_f
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class Hash
|
71
|
+
def self.from_mongo(value)
|
72
|
+
HashWithIndifferentAccess.new(value || {})
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_mongo
|
76
|
+
self
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class Integer
|
81
|
+
def self.to_mongo(value)
|
82
|
+
value_to_i = value.to_i
|
83
|
+
if value_to_i == 0 && value != value_to_i
|
84
|
+
value.to_s =~ /^(0x|0b)?0+/ ? 0 : nil
|
85
|
+
else
|
86
|
+
value_to_i
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class NilClass
|
92
|
+
def to_mongo(value)
|
93
|
+
value
|
94
|
+
end
|
95
|
+
|
96
|
+
def from_mongo(value)
|
97
|
+
value
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class Object
|
102
|
+
# The hidden singleton lurks behind everyone
|
103
|
+
def metaclass
|
104
|
+
class << self; self end
|
105
|
+
end
|
106
|
+
|
107
|
+
def meta_eval(&blk)
|
108
|
+
metaclass.instance_eval(&blk)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Adds methods to a metaclass
|
112
|
+
def meta_def(name, &blk)
|
113
|
+
meta_eval { define_method(name, &blk) }
|
114
|
+
end
|
115
|
+
|
116
|
+
# Defines an instance method within a class
|
117
|
+
def class_def(name, &blk)
|
118
|
+
class_eval { define_method(name, &blk) }
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.to_mongo(value)
|
122
|
+
value
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.from_mongo(value)
|
126
|
+
value
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
class ObjectId
|
131
|
+
def self.to_mongo(value)
|
132
|
+
if value.blank?
|
133
|
+
nil
|
134
|
+
elsif value.is_a?(Mongo::ObjectID)
|
135
|
+
value
|
136
|
+
else
|
137
|
+
Mongo::ObjectID.from_string(value.to_s)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def self.from_mongo(value)
|
142
|
+
value
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
class Set
|
147
|
+
def self.to_mongo(value)
|
148
|
+
value.to_a
|
149
|
+
end
|
150
|
+
|
151
|
+
def self.from_mongo(value)
|
152
|
+
Set.new(value || [])
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
class String
|
157
|
+
def self.to_mongo(value)
|
158
|
+
value.nil? ? nil : value.to_s
|
159
|
+
end
|
160
|
+
|
161
|
+
def self.from_mongo(value)
|
162
|
+
value.nil? ? nil : value.to_s
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
class SymbolOperator
|
167
|
+
def initialize(field, operator, options={})
|
168
|
+
@field, @operator = field, operator
|
169
|
+
end unless method_defined?(:initialize)
|
170
|
+
|
171
|
+
def to_mm_criteria(value)
|
172
|
+
{MongoMapper::FinderOptions.normalized_field(@field) => {"$#{@operator}" => value}}
|
173
|
+
end
|
174
|
+
|
175
|
+
def to_mm_order
|
176
|
+
[@field.to_s, MongoMapper::FinderOptions.normalized_order_direction(@operator)]
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
class Symbol
|
181
|
+
%w(gt lt gte lte ne in nin mod size where exists asc desc).each do |operator|
|
182
|
+
define_method(operator) do
|
183
|
+
SymbolOperator.new(self, operator)
|
184
|
+
end unless method_defined?(operator)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
class Time
|
189
|
+
def self.to_mongo(value)
|
190
|
+
if value.nil? || value == ''
|
191
|
+
nil
|
192
|
+
else
|
193
|
+
time = value.is_a?(Time) ? value : MongoMapper.time_class.parse(value.to_s)
|
194
|
+
# Convert time to milliseconds since BSON stores dates with that accurracy, but Ruby uses microseconds
|
195
|
+
Time.at((time.to_f * 1000).round / 1000.0).utc if time
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def self.from_mongo(value)
|
200
|
+
if MongoMapper.use_time_zone? && value.present?
|
201
|
+
value.in_time_zone(Time.zone)
|
202
|
+
else
|
203
|
+
value
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# TODO: Remove when patch accepted into driver
|
209
|
+
class Mongo::ObjectID
|
210
|
+
def to_json(options = nil)
|
211
|
+
%Q("#{to_s}")
|
212
|
+
end
|
213
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# The purpose of this is to check finding, initializing,
|
2
|
+
# and creating objects (typecasting times/dates and booleans).
|
3
|
+
|
4
|
+
require 'pp'
|
5
|
+
require 'benchmark'
|
6
|
+
require 'rubygems'
|
7
|
+
|
8
|
+
# to test with slow version just do this:
|
9
|
+
# gem 'mongo_mapper', '0.6.10'
|
10
|
+
# and comment out this:
|
11
|
+
$:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
12
|
+
|
13
|
+
require 'mongo_mapper'
|
14
|
+
|
15
|
+
MongoMapper.database = 'testing'
|
16
|
+
|
17
|
+
class Foo
|
18
|
+
include MongoMapper::Document
|
19
|
+
key :approved, Boolean
|
20
|
+
key :count, Integer
|
21
|
+
key :approved_at, Time
|
22
|
+
key :expire_on, Date
|
23
|
+
timestamps!
|
24
|
+
end
|
25
|
+
Foo.collection.remove
|
26
|
+
|
27
|
+
Benchmark.bm(5) do |x|
|
28
|
+
ids = []
|
29
|
+
x.report("write") do
|
30
|
+
1000.times { |i| ids << Foo.create(:count => 0, :approved => true, :approved_at => Time.now, :expire_on => Date.today).id }
|
31
|
+
end
|
32
|
+
|
33
|
+
x.report("read ") do
|
34
|
+
ids.each { |id| Foo.first(:id => id) }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# I was get something like this on my puny macbook air:
|
39
|
+
# user system total real
|
40
|
+
# write 4.810000 0.090000 4.900000 ( 5.039949)
|
41
|
+
# read 2.730000 0.070000 2.800000 ( 2.990749)
|
42
|
+
#
|
43
|
+
#
|
44
|
+
# After these commits:
|
45
|
+
#
|
46
|
+
# * http://github.com/jnunemaker/mongomapper/commit/e5091fa140d5fae2721017b53027092233694ee5
|
47
|
+
# * http://github.com/jnunemaker/mongomapper/commit/c22bbde4fa1cfbc310d79cb0e50203310ffb03d1
|
48
|
+
#
|
49
|
+
# I'm now getting something like this:
|
50
|
+
# user system total real
|
51
|
+
# write 1.660000 0.050000 1.710000 ( 1.752676)
|
52
|
+
# read 1.060000 0.050000 1.110000 ( 1.263429)
|
data/specs.watchr
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
def growl(title, msg, img)
|
2
|
+
%x{growlnotify -m #{ msg.inspect} -t #{title.inspect} --image ~/.watchr/#{img}.png}
|
3
|
+
end
|
4
|
+
|
5
|
+
def form_growl_message(str)
|
6
|
+
results = str.split("\n").last
|
7
|
+
if results =~ /[1-9]\s(failure|error)s?/
|
8
|
+
growl "Test Results", "#{results}", "fail"
|
9
|
+
elsif results != ""
|
10
|
+
growl "Test Results", "#{results}", "pass"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def run(cmd)
|
15
|
+
puts(cmd)
|
16
|
+
output = ""
|
17
|
+
IO.popen(cmd) do |com|
|
18
|
+
com.each_char do |c|
|
19
|
+
print c
|
20
|
+
output << c
|
21
|
+
$stdout.flush
|
22
|
+
end
|
23
|
+
end
|
24
|
+
form_growl_message output
|
25
|
+
end
|
26
|
+
|
27
|
+
def run_test_file(file)
|
28
|
+
run %Q(ruby -I"lib:test" -rubygems #{file})
|
29
|
+
end
|
30
|
+
|
31
|
+
def run_all_tests
|
32
|
+
run "rake test"
|
33
|
+
end
|
34
|
+
|
35
|
+
def related_test_files(path)
|
36
|
+
Dir['test/**/*.rb'].select { |file| file =~ /test_#{File.basename(path)}/ }
|
37
|
+
end
|
38
|
+
|
39
|
+
watch('test/test_helper\.rb') { system('clear'); run_all_tests }
|
40
|
+
watch('test/.*/test_.*\.rb') { |m| system('clear'); run_test_file(m[0]) }
|
41
|
+
watch('lib/.*') { |m| related_test_files(m[0]).each { |file| run_test_file(file) } }
|
42
|
+
|
43
|
+
# Ctrl-\
|
44
|
+
Signal.trap('QUIT') do
|
45
|
+
puts " --- Running all tests ---\n\n"
|
46
|
+
run_all_tests
|
47
|
+
end
|
48
|
+
|
49
|
+
# Ctrl-C
|
50
|
+
Signal.trap('INT') { abort("\n") }
|
51
|
+
|