activerecord 1.6.0 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- data/CHANGELOG +78 -0
- data/README +20 -29
- data/RUNNING_UNIT_TESTS +1 -2
- data/examples/validation.rb +0 -3
- data/install.rb +3 -16
- data/lib/active_record.rb +11 -4
- data/lib/active_record/aggregations.rb +2 -2
- data/lib/active_record/associations.rb +8 -8
- data/lib/active_record/associations/association_collection.rb +1 -1
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +1 -1
- data/lib/active_record/base.rb +117 -43
- data/lib/active_record/callbacks.rb +2 -2
- data/lib/active_record/connection_adapters/abstract_adapter.rb +7 -14
- data/lib/active_record/connection_adapters/db2_adapter.rb +33 -22
- data/lib/active_record/connection_adapters/mysql_adapter.rb +74 -33
- data/lib/active_record/connection_adapters/oci_adapter.rb +265 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +23 -3
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +13 -4
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +158 -67
- data/lib/active_record/deprecated_associations.rb +4 -4
- data/lib/active_record/fixtures.rb +12 -5
- data/lib/active_record/locking.rb +22 -22
- data/lib/active_record/observer.rb +6 -3
- data/lib/active_record/timestamp.rb +15 -5
- data/lib/active_record/transactions.rb +4 -4
- data/lib/active_record/validations.rb +272 -189
- data/lib/active_record/wrappings.rb +2 -2
- data/rakefile +17 -2
- data/test/aaa_create_tables_test.rb +58 -0
- data/test/abstract_unit.rb +3 -2
- data/test/aggregations_test.rb +0 -1
- data/test/associations_test.rb +27 -28
- data/test/base_test.rb +74 -2
- data/test/binary_test.rb +6 -2
- data/test/class_inheritable_attributes_test.rb +1 -1
- data/test/column_alias_test.rb +9 -2
- data/test/connections/native_oci/connection.rb +25 -0
- data/test/connections/native_sqlite/connection.rb +4 -1
- data/test/connections/native_sqlite3/connection.rb +4 -2
- data/test/deprecated_associations_test.rb +4 -5
- data/test/finder_test.rb +20 -4
- data/test/fixtures/db_definitions/create_oracle_db.bat +5 -0
- data/test/fixtures/db_definitions/create_oracle_db.sh +5 -0
- data/test/fixtures/db_definitions/db2.drop.sql +18 -0
- data/test/fixtures/db_definitions/db2.sql +1 -0
- data/test/fixtures/db_definitions/db22.drop.sql +2 -0
- data/test/fixtures/db_definitions/db22.sql +1 -0
- data/test/fixtures/db_definitions/drop_oracle_tables.sql +35 -0
- data/test/fixtures/db_definitions/drop_oracle_tables2.sql +3 -0
- data/test/fixtures/db_definitions/mysql.drop.sql +18 -0
- data/test/fixtures/db_definitions/mysql.sql +2 -1
- data/test/fixtures/db_definitions/mysql2.drop.sql +2 -0
- data/test/fixtures/db_definitions/mysql2.sql +1 -0
- data/test/fixtures/db_definitions/oci.drop.sql +18 -0
- data/test/fixtures/db_definitions/oci.sql +167 -0
- data/test/fixtures/db_definitions/oci2.drop.sql +2 -0
- data/test/fixtures/db_definitions/oci2.sql +6 -0
- data/test/fixtures/db_definitions/postgresql.drop.sql +18 -0
- data/test/fixtures/db_definitions/postgresql.sql +2 -1
- data/test/fixtures/db_definitions/postgresql2.drop.sql +2 -0
- data/test/fixtures/db_definitions/postgresql2.sql +2 -1
- data/test/fixtures/db_definitions/sqlite.drop.sql +18 -0
- data/test/fixtures/db_definitions/sqlite.sql +2 -1
- data/test/fixtures/db_definitions/sqlite2.drop.sql +2 -0
- data/test/fixtures/db_definitions/sqlite2.sql +1 -0
- data/test/fixtures/db_definitions/sqlserver.drop.sql +18 -0
- data/test/fixtures/db_definitions/sqlserver.sql +1 -0
- data/test/fixtures/db_definitions/sqlserver2.drop.sql +2 -0
- data/test/fixtures/db_definitions/sqlserver2.sql +1 -0
- data/test/fixtures/fixture_database.sqlite +0 -0
- data/test/fixtures/fixture_database_2.sqlite +0 -0
- data/test/fixtures/topics.yml +3 -3
- data/test/lifecycle_test.rb +0 -1
- data/test/modules_test.rb +0 -1
- data/test/reflection_test.rb +0 -1
- data/test/validations_test.rb +229 -41
- metadata +36 -28
- data/dev-utils/eval_debugger.rb +0 -14
- data/lib/active_record/support/binding_of_caller.rb +0 -83
- data/lib/active_record/support/breakpoint.rb +0 -518
- data/lib/active_record/support/class_attribute_accessors.rb +0 -57
- data/lib/active_record/support/class_inheritable_attributes.rb +0 -117
- data/lib/active_record/support/clean_logger.rb +0 -10
- data/lib/active_record/support/core_ext.rb +0 -1
- data/lib/active_record/support/core_ext/hash.rb +0 -5
- data/lib/active_record/support/core_ext/hash/keys.rb +0 -35
- data/lib/active_record/support/core_ext/numeric.rb +0 -7
- data/lib/active_record/support/core_ext/numeric/bytes.rb +0 -33
- data/lib/active_record/support/core_ext/numeric/time.rb +0 -59
- data/lib/active_record/support/core_ext/object_and_class.rb +0 -24
- data/lib/active_record/support/core_ext/string.rb +0 -5
- data/lib/active_record/support/core_ext/string/inflections.rb +0 -45
- data/lib/active_record/support/dependencies.rb +0 -63
- data/lib/active_record/support/inflector.rb +0 -84
- data/lib/active_record/support/misc.rb +0 -8
- data/lib/active_record/support/module_attribute_accessors.rb +0 -57
metadata
CHANGED
@@ -3,13 +3,13 @@ rubygems_version: 0.8.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: activerecord
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.
|
7
|
-
date: 2005-
|
6
|
+
version: 1.7.0
|
7
|
+
date: 2005-02-24
|
8
8
|
summary: Implements the ActiveRecord pattern for ORM.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
11
11
|
email: david@loudthinking.com
|
12
|
-
homepage: http://www.rubyonrails.
|
12
|
+
homepage: http://www.rubyonrails.org
|
13
13
|
rubyforge_project: activerecord
|
14
14
|
description: "Implements the ActiveRecord pattern (Fowler, PoEAA) for ORM. It ties database
|
15
15
|
tables and classes together for business objects, like Customer or Subscription,
|
@@ -48,7 +48,6 @@ files:
|
|
48
48
|
- lib/active_record/locking.rb
|
49
49
|
- lib/active_record/observer.rb
|
50
50
|
- lib/active_record/reflection.rb
|
51
|
-
- lib/active_record/support
|
52
51
|
- lib/active_record/timestamp.rb
|
53
52
|
- lib/active_record/transactions.rb
|
54
53
|
- lib/active_record/validations.rb
|
@@ -66,36 +65,16 @@ files:
|
|
66
65
|
- lib/active_record/connection_adapters/abstract_adapter.rb
|
67
66
|
- lib/active_record/connection_adapters/db2_adapter.rb
|
68
67
|
- lib/active_record/connection_adapters/mysql_adapter.rb
|
68
|
+
- lib/active_record/connection_adapters/oci_adapter.rb
|
69
69
|
- lib/active_record/connection_adapters/postgresql_adapter.rb
|
70
70
|
- lib/active_record/connection_adapters/sqlite_adapter.rb
|
71
71
|
- lib/active_record/connection_adapters/sqlserver_adapter.rb
|
72
|
-
- lib/active_record/support/binding_of_caller.rb
|
73
|
-
- lib/active_record/support/breakpoint.rb
|
74
|
-
- lib/active_record/support/class_attribute_accessors.rb
|
75
|
-
- lib/active_record/support/class_inheritable_attributes.rb
|
76
|
-
- lib/active_record/support/clean_logger.rb
|
77
|
-
- lib/active_record/support/core_ext
|
78
|
-
- lib/active_record/support/core_ext.rb
|
79
|
-
- lib/active_record/support/dependencies.rb
|
80
|
-
- lib/active_record/support/inflector.rb
|
81
|
-
- lib/active_record/support/misc.rb
|
82
|
-
- lib/active_record/support/module_attribute_accessors.rb
|
83
|
-
- lib/active_record/support/core_ext/hash
|
84
|
-
- lib/active_record/support/core_ext/hash.rb
|
85
|
-
- lib/active_record/support/core_ext/numeric
|
86
|
-
- lib/active_record/support/core_ext/numeric.rb
|
87
|
-
- lib/active_record/support/core_ext/object_and_class.rb
|
88
|
-
- lib/active_record/support/core_ext/string
|
89
|
-
- lib/active_record/support/core_ext/string.rb
|
90
|
-
- lib/active_record/support/core_ext/hash/keys.rb
|
91
|
-
- lib/active_record/support/core_ext/numeric/bytes.rb
|
92
|
-
- lib/active_record/support/core_ext/numeric/time.rb
|
93
|
-
- lib/active_record/support/core_ext/string/inflections.rb
|
94
72
|
- lib/active_record/vendor/db2.rb
|
95
73
|
- lib/active_record/vendor/mysql.rb
|
96
74
|
- lib/active_record/vendor/mysql411.rb
|
97
75
|
- lib/active_record/vendor/simple.rb
|
98
76
|
- lib/active_record/wrappers/yaml_wrapper.rb
|
77
|
+
- test/aaa_create_tables_test.rb
|
99
78
|
- test/abstract_unit.rb
|
100
79
|
- test/aggregations_test.rb
|
101
80
|
- test/all.sh
|
@@ -125,12 +104,14 @@ files:
|
|
125
104
|
- test/validations_test.rb
|
126
105
|
- test/connections/native_db2
|
127
106
|
- test/connections/native_mysql
|
107
|
+
- test/connections/native_oci
|
128
108
|
- test/connections/native_postgresql
|
129
109
|
- test/connections/native_sqlite
|
130
110
|
- test/connections/native_sqlite3
|
131
111
|
- test/connections/native_sqlserver
|
132
112
|
- test/connections/native_db2/connection.rb
|
133
113
|
- test/connections/native_mysql/connection.rb
|
114
|
+
- test/connections/native_oci/connection.rb
|
134
115
|
- test/connections/native_postgresql/connection.rb
|
135
116
|
- test/connections/native_sqlite/connection.rb
|
136
117
|
- test/connections/native_sqlite3/connection.rb
|
@@ -179,15 +160,33 @@ files:
|
|
179
160
|
- test/fixtures/bad_fixtures/blank_line
|
180
161
|
- test/fixtures/bad_fixtures/duplicate_attributes
|
181
162
|
- test/fixtures/bad_fixtures/missing_value
|
163
|
+
- test/fixtures/db_definitions/create_oracle_db.bat
|
164
|
+
- test/fixtures/db_definitions/create_oracle_db.sh
|
165
|
+
- test/fixtures/db_definitions/db2.drop.sql
|
182
166
|
- test/fixtures/db_definitions/db2.sql
|
167
|
+
- test/fixtures/db_definitions/db22.drop.sql
|
183
168
|
- test/fixtures/db_definitions/db22.sql
|
169
|
+
- test/fixtures/db_definitions/drop_oracle_tables.sql
|
170
|
+
- test/fixtures/db_definitions/drop_oracle_tables2.sql
|
171
|
+
- test/fixtures/db_definitions/mysql.drop.sql
|
184
172
|
- test/fixtures/db_definitions/mysql.sql
|
173
|
+
- test/fixtures/db_definitions/mysql2.drop.sql
|
185
174
|
- test/fixtures/db_definitions/mysql2.sql
|
175
|
+
- test/fixtures/db_definitions/oci.drop.sql
|
176
|
+
- test/fixtures/db_definitions/oci.sql
|
177
|
+
- test/fixtures/db_definitions/oci2.drop.sql
|
178
|
+
- test/fixtures/db_definitions/oci2.sql
|
179
|
+
- test/fixtures/db_definitions/postgresql.drop.sql
|
186
180
|
- test/fixtures/db_definitions/postgresql.sql
|
181
|
+
- test/fixtures/db_definitions/postgresql2.drop.sql
|
187
182
|
- test/fixtures/db_definitions/postgresql2.sql
|
183
|
+
- test/fixtures/db_definitions/sqlite.drop.sql
|
188
184
|
- test/fixtures/db_definitions/sqlite.sql
|
185
|
+
- test/fixtures/db_definitions/sqlite2.drop.sql
|
189
186
|
- test/fixtures/db_definitions/sqlite2.sql
|
187
|
+
- test/fixtures/db_definitions/sqlserver.drop.sql
|
190
188
|
- test/fixtures/db_definitions/sqlserver.sql
|
189
|
+
- test/fixtures/db_definitions/sqlserver2.drop.sql
|
191
190
|
- test/fixtures/db_definitions/sqlserver2.sql
|
192
191
|
- test/fixtures/developers_projects/david_action_controller
|
193
192
|
- test/fixtures/developers_projects/david_active_record
|
@@ -204,7 +203,6 @@ files:
|
|
204
203
|
- examples/associations.rb
|
205
204
|
- examples/shared_setup.rb
|
206
205
|
- examples/validation.rb
|
207
|
-
- dev-utils/eval_debugger.rb
|
208
206
|
test_files: []
|
209
207
|
rdoc_options:
|
210
208
|
- "--main"
|
@@ -214,4 +212,14 @@ extra_rdoc_files:
|
|
214
212
|
executables: []
|
215
213
|
extensions: []
|
216
214
|
requirements: []
|
217
|
-
dependencies:
|
215
|
+
dependencies:
|
216
|
+
- !ruby/object:Gem::Dependency
|
217
|
+
name: activesupport
|
218
|
+
version_requirement:
|
219
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
220
|
+
requirements:
|
221
|
+
-
|
222
|
+
- "="
|
223
|
+
- !ruby/object:Gem::Version
|
224
|
+
version: 1.0.0
|
225
|
+
version:
|
data/dev-utils/eval_debugger.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
# Require this file to see the methods Active Record generates as they are added.
|
2
|
-
class Module #:nodoc:
|
3
|
-
alias :old_module_eval :module_eval
|
4
|
-
def module_eval(*args, &block)
|
5
|
-
if args[0]
|
6
|
-
puts "----"
|
7
|
-
print "module_eval in #{self.name}"
|
8
|
-
print ": file #{args[1]}" if args[1]
|
9
|
-
print " on line #{args[2]}" if args[2]
|
10
|
-
puts "\n#{args[0]}"
|
11
|
-
end
|
12
|
-
old_module_eval(*args, &block)
|
13
|
-
end
|
14
|
-
end
|
@@ -1,83 +0,0 @@
|
|
1
|
-
begin
|
2
|
-
require 'simplecc'
|
3
|
-
rescue LoadError
|
4
|
-
class Continuation; end # :nodoc: # for RDoc
|
5
|
-
def Continuation.create(*args, &block) # :nodoc:
|
6
|
-
cc = nil; result = callcc {|c| cc = c; block.call(cc) if block and args.empty?}
|
7
|
-
result ||= args
|
8
|
-
return *[cc, *result]
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
class Binding; end # for RDoc
|
13
|
-
# This method returns the binding of the method that called your
|
14
|
-
# method. It will raise an Exception when you're not inside a method.
|
15
|
-
#
|
16
|
-
# It's used like this:
|
17
|
-
# def inc_counter(amount = 1)
|
18
|
-
# Binding.of_caller do |binding|
|
19
|
-
# # Create a lambda that will increase the variable 'counter'
|
20
|
-
# # in the caller of this method when called.
|
21
|
-
# inc = eval("lambda { |arg| counter += arg }", binding)
|
22
|
-
# # We can refer to amount from inside this block safely.
|
23
|
-
# inc.call(amount)
|
24
|
-
# end
|
25
|
-
# # No other statements can go here. Put them inside the block.
|
26
|
-
# end
|
27
|
-
# counter = 0
|
28
|
-
# 2.times { inc_counter }
|
29
|
-
# counter # => 2
|
30
|
-
#
|
31
|
-
# Binding.of_caller must be the last statement in the method.
|
32
|
-
# This means that you will have to put everything you want to
|
33
|
-
# do after the call to Binding.of_caller into the block of it.
|
34
|
-
# This should be no problem however, because Ruby has closures.
|
35
|
-
# If you don't do this an Exception will be raised. Because of
|
36
|
-
# the way that Binding.of_caller is implemented it has to be
|
37
|
-
# done this way.
|
38
|
-
def Binding.of_caller(&block)
|
39
|
-
old_critical = Thread.critical
|
40
|
-
Thread.critical = true
|
41
|
-
count = 0
|
42
|
-
cc, result, error, extra_data = Continuation.create(nil, nil)
|
43
|
-
error.call if error
|
44
|
-
|
45
|
-
tracer = lambda do |*args|
|
46
|
-
type, context, extra_data = args[0], args[4], args
|
47
|
-
if type == "return"
|
48
|
-
count += 1
|
49
|
-
# First this method and then calling one will return --
|
50
|
-
# the trace event of the second event gets the context
|
51
|
-
# of the method which called the method that called this
|
52
|
-
# method.
|
53
|
-
if count == 2
|
54
|
-
# It would be nice if we could restore the trace_func
|
55
|
-
# that was set before we swapped in our own one, but
|
56
|
-
# this is impossible without overloading set_trace_func
|
57
|
-
# in current Ruby.
|
58
|
-
set_trace_func(nil)
|
59
|
-
cc.call(eval("binding", context), nil, extra_data)
|
60
|
-
end
|
61
|
-
elsif type == "line" then
|
62
|
-
nil
|
63
|
-
elsif type == "c-return" and extra_data[3] == :set_trace_func then
|
64
|
-
nil
|
65
|
-
else
|
66
|
-
set_trace_func(nil)
|
67
|
-
error_msg = "Binding.of_caller used in non-method context or " +
|
68
|
-
"trailing statements of method using it aren't in the block."
|
69
|
-
cc.call(nil, lambda { raise(ArgumentError, error_msg) }, nil)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
unless result
|
74
|
-
set_trace_func(tracer)
|
75
|
-
return nil
|
76
|
-
else
|
77
|
-
Thread.critical = old_critical
|
78
|
-
case block.arity
|
79
|
-
when 1 then yield(result)
|
80
|
-
else yield(result, extra_data)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
@@ -1,518 +0,0 @@
|
|
1
|
-
# The Breakpoint library provides the convenience of
|
2
|
-
# being able to inspect and modify state, diagnose
|
3
|
-
# bugs all via IRB by simply setting breakpoints in
|
4
|
-
# your applications by the call of a method.
|
5
|
-
#
|
6
|
-
# This library was written and is supported by me,
|
7
|
-
# Florian Gross. I can be reached at flgr@ccan.de
|
8
|
-
# and enjoy getting feedback about my libraries.
|
9
|
-
#
|
10
|
-
# The whole library (including breakpoint_client.rb
|
11
|
-
# and binding_of_caller.rb) is licensed under the
|
12
|
-
# same license that Ruby uses. (Which is currently
|
13
|
-
# either the GNU General Public License or a custom
|
14
|
-
# one that allows for commercial usage.) If you for
|
15
|
-
# some good reason need to use this under another
|
16
|
-
# license please contact me.
|
17
|
-
|
18
|
-
require 'irb'
|
19
|
-
require File.dirname(__FILE__) + '/binding_of_caller'
|
20
|
-
require 'drb'
|
21
|
-
require 'drb/acl'
|
22
|
-
|
23
|
-
module Breakpoint
|
24
|
-
id = %q$Id: breakpoint.rb 41 2005-01-22 20:22:10Z flgr $
|
25
|
-
Version = id.split(" ")[2].to_i
|
26
|
-
|
27
|
-
extend self
|
28
|
-
|
29
|
-
# This will pop up an interactive ruby session at a
|
30
|
-
# pre-defined break point in a Ruby application. In
|
31
|
-
# this session you can examine the environment of
|
32
|
-
# the break point.
|
33
|
-
#
|
34
|
-
# You can get a list of variables in the context using
|
35
|
-
# local_variables via +local_variables+. You can then
|
36
|
-
# examine their values by typing their names.
|
37
|
-
#
|
38
|
-
# You can have a look at the call stack via +caller+.
|
39
|
-
#
|
40
|
-
# The source code around the location where the breakpoint
|
41
|
-
# was executed can be examined via +source_lines+. Its
|
42
|
-
# argument specifies how much lines of context to display.
|
43
|
-
# The default amount of context is 5 lines. Note that
|
44
|
-
# the call to +source_lines+ can raise an exception when
|
45
|
-
# it isn't able to read in the source code.
|
46
|
-
#
|
47
|
-
# breakpoints can also return a value. They will execute
|
48
|
-
# a supplied block for getting a default return value.
|
49
|
-
# A custom value can be returned from the session by doing
|
50
|
-
# +throw(:debug_return, value)+.
|
51
|
-
#
|
52
|
-
# You can also give names to break points which will be
|
53
|
-
# used in the message that is displayed upon execution
|
54
|
-
# of them.
|
55
|
-
#
|
56
|
-
# Here's a sample of how breakpoints should be placed:
|
57
|
-
#
|
58
|
-
# class Person
|
59
|
-
# def initialize(name, age)
|
60
|
-
# @name, @age = name, age
|
61
|
-
# breakpoint("Person#initialize")
|
62
|
-
# end
|
63
|
-
#
|
64
|
-
# attr_reader :age
|
65
|
-
# def name
|
66
|
-
# breakpoint("Person#name") { @name }
|
67
|
-
# end
|
68
|
-
# end
|
69
|
-
#
|
70
|
-
# person = Person.new("Random Person", 23)
|
71
|
-
# puts "Name: #{person.name}"
|
72
|
-
#
|
73
|
-
# And here is a sample debug session:
|
74
|
-
#
|
75
|
-
# Executing break point "Person#initialize" at file.rb:4 in `initialize'
|
76
|
-
# irb(#<Person:0x292fbe8>):001:0> local_variables
|
77
|
-
# => ["name", "age", "_", "__"]
|
78
|
-
# irb(#<Person:0x292fbe8>):002:0> [name, age]
|
79
|
-
# => ["Random Person", 23]
|
80
|
-
# irb(#<Person:0x292fbe8>):003:0> [@name, @age]
|
81
|
-
# => ["Random Person", 23]
|
82
|
-
# irb(#<Person:0x292fbe8>):004:0> self
|
83
|
-
# => #<Person:0x292fbe8 @age=23, @name="Random Person">
|
84
|
-
# irb(#<Person:0x292fbe8>):005:0> @age += 1; self
|
85
|
-
# => #<Person:0x292fbe8 @age=24, @name="Random Person">
|
86
|
-
# irb(#<Person:0x292fbe8>):006:0> exit
|
87
|
-
# Executing break point "Person#name" at file.rb:9 in `name'
|
88
|
-
# irb(#<Person:0x292fbe8>):001:0> throw(:debug_return, "Overriden name")
|
89
|
-
# Name: Overriden name
|
90
|
-
#
|
91
|
-
# Breakpoint sessions will automatically have a few
|
92
|
-
# convenience methods available. See Breakpoint::CommandBundle
|
93
|
-
# for a list of them.
|
94
|
-
#
|
95
|
-
# Breakpoints can also be used remotely over sockets.
|
96
|
-
# This is implemented by running part of the IRB session
|
97
|
-
# in the application and part of it in a special client.
|
98
|
-
# You have to call Breakpoint.activate_drb to enable
|
99
|
-
# support for remote breakpoints and then run
|
100
|
-
# breakpoint_client.rb which is distributed with this
|
101
|
-
# library. See the documentation of Breakpoint.activate_drb
|
102
|
-
# for details.
|
103
|
-
def breakpoint(id = nil, context = nil, &block)
|
104
|
-
callstack = caller
|
105
|
-
callstack.slice!(0, 3) if callstack.first["breakpoint"]
|
106
|
-
file, line, method = *callstack.first.match(/^(.+?):(\d+)(?::in `(.*?)')?/).captures
|
107
|
-
|
108
|
-
message = "Executing break point " + (id ? "#{id.inspect} " : "") +
|
109
|
-
"at #{file}:#{line}" + (method ? " in `#{method}'" : "")
|
110
|
-
|
111
|
-
if context then
|
112
|
-
return handle_breakpoint(context, message, file, line, &block)
|
113
|
-
end
|
114
|
-
|
115
|
-
Binding.of_caller do |binding_context|
|
116
|
-
handle_breakpoint(binding_context, message, file, line, &block)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
module CommandBundle
|
121
|
-
# Proxy to a Breakpoint client. Lets you directly execute code
|
122
|
-
# in the context of the client.
|
123
|
-
class Client
|
124
|
-
def initialize(eval_handler) # :nodoc:
|
125
|
-
@eval_handler = eval_handler
|
126
|
-
end
|
127
|
-
|
128
|
-
instance_methods.each do |method|
|
129
|
-
next if method[/^__.+__$/]
|
130
|
-
undef_method method
|
131
|
-
end
|
132
|
-
|
133
|
-
# Executes the specified code at the client.
|
134
|
-
def eval(code)
|
135
|
-
@eval_handler.call(code)
|
136
|
-
end
|
137
|
-
|
138
|
-
# Will execute the specified statement at the client.
|
139
|
-
def method_missing(method, *args, &block)
|
140
|
-
if args.empty? and not block
|
141
|
-
result = eval "#{method}"
|
142
|
-
else
|
143
|
-
# This is a bit ugly. The alternative would be using an
|
144
|
-
# eval context instead of an eval handler for executing
|
145
|
-
# the code at the client. The problem with that approach
|
146
|
-
# is that we would have to handle special expressions
|
147
|
-
# like "self", "nil" or constants ourself which is hard.
|
148
|
-
remote = eval %{
|
149
|
-
result = lambda { |block, *args| #{method}(*args, &block) }
|
150
|
-
def result.call_with_block(*args, &block)
|
151
|
-
call(block, *args)
|
152
|
-
end
|
153
|
-
result
|
154
|
-
}
|
155
|
-
remote.call_with_block(*args, &block)
|
156
|
-
end
|
157
|
-
|
158
|
-
return result
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
# Returns the source code surrounding the location where the
|
163
|
-
# breakpoint was issued.
|
164
|
-
def source_lines(context = 5, return_line_numbers = false)
|
165
|
-
lines = File.readlines(@__bp_file).map { |line| line.chomp }
|
166
|
-
|
167
|
-
break_line = @__bp_line
|
168
|
-
start_line = [break_line - context, 1].max
|
169
|
-
end_line = break_line + context
|
170
|
-
|
171
|
-
result = lines[(start_line - 1) .. (end_line - 1)]
|
172
|
-
|
173
|
-
if return_line_numbers then
|
174
|
-
return [start_line, break_line, result]
|
175
|
-
else
|
176
|
-
return result
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
# Lets an object that will forward method calls to the breakpoint
|
181
|
-
# client. This is useful for outputting longer things at the client
|
182
|
-
# and so on. You can for example do these things:
|
183
|
-
#
|
184
|
-
# client.puts "Hello" # outputs "Hello" at client console
|
185
|
-
# # outputs "Hello" into the file temp.txt at the client
|
186
|
-
# client.File.open("temp.txt", "w") { |f| f.puts "Hello" }
|
187
|
-
def client()
|
188
|
-
if Breakpoint.use_drb? then
|
189
|
-
sleep(0.5) until Breakpoint.drb_service.eval_handler
|
190
|
-
Client.new(Breakpoint.drb_service.eval_handler)
|
191
|
-
else
|
192
|
-
Client.new(lambda { |code| eval(code, TOPLEVEL_BINDING) })
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
def handle_breakpoint(context, message, file = "", line = "", &block) # :nodoc:
|
198
|
-
catch(:debug_return) do |value|
|
199
|
-
eval(%{
|
200
|
-
@__bp_file = #{file.inspect}
|
201
|
-
@__bp_line = #{line}
|
202
|
-
extend Breakpoint::CommandBundle
|
203
|
-
extend DRbUndumped if self
|
204
|
-
}, context) rescue nil
|
205
|
-
|
206
|
-
if not use_drb? then
|
207
|
-
puts message
|
208
|
-
IRB.start(nil, IRB::WorkSpace.new(context))
|
209
|
-
else
|
210
|
-
@drb_service.add_breakpoint(context, message)
|
211
|
-
end
|
212
|
-
|
213
|
-
block.call if block
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
# These exceptions will be raised on failed asserts
|
218
|
-
# if Breakpoint.asserts_cause_exceptions is set to
|
219
|
-
# true.
|
220
|
-
class FailedAssertError < RuntimeError
|
221
|
-
end
|
222
|
-
|
223
|
-
# This asserts that the block evaluates to true.
|
224
|
-
# If it doesn't evaluate to true a breakpoint will
|
225
|
-
# automatically be created at that execution point.
|
226
|
-
#
|
227
|
-
# You can disable assert checking in production
|
228
|
-
# code by setting Breakpoint.optimize_asserts to
|
229
|
-
# true. (It will still be enabled when Ruby is run
|
230
|
-
# via the -d argument.)
|
231
|
-
#
|
232
|
-
# Example:
|
233
|
-
# person_name = "Foobar"
|
234
|
-
# assert { not person_name.nil? }
|
235
|
-
#
|
236
|
-
# Note: If you want to use this method from an
|
237
|
-
# unit test, you will have to call it by its full
|
238
|
-
# name, Breakpoint.assert.
|
239
|
-
def assert(context = nil, &condition)
|
240
|
-
return if Breakpoint.optimize_asserts and not $DEBUG
|
241
|
-
return if yield
|
242
|
-
|
243
|
-
callstack = caller
|
244
|
-
callstack.slice!(0, 3) if callstack.first["assert"]
|
245
|
-
file, line, method = *callstack.first.match(/^(.+?):(\d+)(?::in `(.*?)')?/).captures
|
246
|
-
|
247
|
-
message = "Assert failed at #{file}:#{line}#{" in `#{method}'" if method}."
|
248
|
-
|
249
|
-
if Breakpoint.asserts_cause_exceptions and not $DEBUG then
|
250
|
-
raise(Breakpoint::FailedAssertError, message)
|
251
|
-
end
|
252
|
-
|
253
|
-
message += " Executing implicit breakpoint."
|
254
|
-
|
255
|
-
if context then
|
256
|
-
return handle_breakpoint(context, message, file, line)
|
257
|
-
end
|
258
|
-
|
259
|
-
Binding.of_caller do |context|
|
260
|
-
handle_breakpoint(context, message, file, line)
|
261
|
-
end
|
262
|
-
end
|
263
|
-
|
264
|
-
# Whether asserts should be ignored if not in debug mode.
|
265
|
-
# Debug mode can be enabled by running ruby with the -d
|
266
|
-
# switch or by setting $DEBUG to true.
|
267
|
-
attr_accessor :optimize_asserts
|
268
|
-
self.optimize_asserts = false
|
269
|
-
|
270
|
-
# Whether an Exception should be raised on failed asserts
|
271
|
-
# in non-$DEBUG code or not. By default this is disabled.
|
272
|
-
attr_accessor :asserts_cause_exceptions
|
273
|
-
self.asserts_cause_exceptions = false
|
274
|
-
@use_drb = false
|
275
|
-
|
276
|
-
attr_reader :drb_service # :nodoc:
|
277
|
-
|
278
|
-
class DRbService # :nodoc:
|
279
|
-
include DRbUndumped
|
280
|
-
|
281
|
-
def initialize
|
282
|
-
@handler = @eval_handler = @collision_handler = nil
|
283
|
-
|
284
|
-
IRB.instance_eval { @CONF[:RC] = true }
|
285
|
-
IRB.run_config
|
286
|
-
end
|
287
|
-
|
288
|
-
def collision
|
289
|
-
sleep(0.5) until @collision_handler
|
290
|
-
|
291
|
-
@collision_handler.call
|
292
|
-
end
|
293
|
-
|
294
|
-
def ping() end
|
295
|
-
|
296
|
-
def add_breakpoint(context, message)
|
297
|
-
workspace = IRB::WorkSpace.new(context)
|
298
|
-
workspace.extend(DRbUndumped)
|
299
|
-
|
300
|
-
sleep(0.5) until @handler
|
301
|
-
|
302
|
-
@handler.call(workspace, message)
|
303
|
-
end
|
304
|
-
|
305
|
-
attr_accessor :handler, :eval_handler, :collision_handler
|
306
|
-
end
|
307
|
-
|
308
|
-
# Will run Breakpoint in DRb mode. This will spawn a server
|
309
|
-
# that can be attached to via the breakpoint-client command
|
310
|
-
# whenever a breakpoint is executed. This is useful when you
|
311
|
-
# are debugging CGI applications or other applications where
|
312
|
-
# you can't access debug sessions via the standard input and
|
313
|
-
# output of your application.
|
314
|
-
#
|
315
|
-
# You can specify an URI where the DRb server will run at.
|
316
|
-
# This way you can specify the port the server runs on. The
|
317
|
-
# default URI is druby://localhost:42531.
|
318
|
-
#
|
319
|
-
# Please note that breakpoints will be skipped silently in
|
320
|
-
# case the DRb server can not spawned. (This can happen if
|
321
|
-
# the port is already used by another instance of your
|
322
|
-
# application on CGI or another application.)
|
323
|
-
#
|
324
|
-
# Also note that by default this will only allow access
|
325
|
-
# from localhost. You can however specify a list of
|
326
|
-
# allowed hosts or nil (to allow access from everywhere).
|
327
|
-
# But that will still not protect you from somebody
|
328
|
-
# reading the data as it goes through the net.
|
329
|
-
#
|
330
|
-
# A good approach for getting security and remote access
|
331
|
-
# is setting up an SSH tunnel between the DRb service
|
332
|
-
# and the client. This is usually done like this:
|
333
|
-
#
|
334
|
-
# $ ssh -L20000:127.0.0.1:20000 -R10000:127.0.0.1:10000 example.com
|
335
|
-
# (This will connect port 20000 at the client side to port
|
336
|
-
# 20000 at the server side, and port 10000 at the server
|
337
|
-
# side to port 10000 at the client side.)
|
338
|
-
#
|
339
|
-
# After that do this on the server side: (the code being debugged)
|
340
|
-
# Breakpoint.activate_drb("druby://127.0.0.1:20000", "localhost")
|
341
|
-
#
|
342
|
-
# And at the client side:
|
343
|
-
# ruby breakpoint_client.rb -c druby://127.0.0.1:10000 -s druby://127.0.0.1:20000
|
344
|
-
#
|
345
|
-
# Running through such a SSH proxy will also let you use
|
346
|
-
# breakpoint.rb in case you are behind a firewall.
|
347
|
-
#
|
348
|
-
# Detailed information about running DRb through firewalls is
|
349
|
-
# available at http://www.rubygarden.org/ruby?DrbTutorial
|
350
|
-
def activate_drb(uri = nil, allowed_hosts = ['localhost', '127.0.0.1', '::1'],
|
351
|
-
ignore_collisions = false)
|
352
|
-
|
353
|
-
return false if @use_drb
|
354
|
-
|
355
|
-
uri ||= 'druby://localhost:42531'
|
356
|
-
|
357
|
-
if allowed_hosts then
|
358
|
-
acl = ["deny", "all"]
|
359
|
-
|
360
|
-
Array(allowed_hosts).each do |host|
|
361
|
-
acl += ["allow", host]
|
362
|
-
end
|
363
|
-
|
364
|
-
DRb.install_acl(ACL.new(acl))
|
365
|
-
end
|
366
|
-
|
367
|
-
@use_drb = true
|
368
|
-
@drb_service = DRbService.new
|
369
|
-
did_collision = false
|
370
|
-
begin
|
371
|
-
@service = DRb.start_service(uri, @drb_service)
|
372
|
-
rescue Errno::EADDRINUSE
|
373
|
-
if ignore_collisions then
|
374
|
-
nil
|
375
|
-
else
|
376
|
-
# The port is already occupied by another
|
377
|
-
# Breakpoint service. We will try to tell
|
378
|
-
# the old service that we want its port.
|
379
|
-
# It will then forward that request to the
|
380
|
-
# user and retry.
|
381
|
-
unless did_collision then
|
382
|
-
DRbObject.new(nil, uri).collision
|
383
|
-
did_collision = true
|
384
|
-
end
|
385
|
-
sleep(10)
|
386
|
-
retry
|
387
|
-
end
|
388
|
-
end
|
389
|
-
|
390
|
-
return true
|
391
|
-
end
|
392
|
-
|
393
|
-
# Deactivates a running Breakpoint service.
|
394
|
-
def deactivate_drb
|
395
|
-
@service.stop_service unless @service.nil?
|
396
|
-
@service = nil
|
397
|
-
@use_drb = false
|
398
|
-
@drb_service = nil
|
399
|
-
end
|
400
|
-
|
401
|
-
# Returns true when Breakpoints are used over DRb.
|
402
|
-
# Breakpoint.activate_drb causes this to be true.
|
403
|
-
def use_drb?
|
404
|
-
@use_drb == true
|
405
|
-
end
|
406
|
-
end
|
407
|
-
|
408
|
-
module IRB # :nodoc:
|
409
|
-
class << self; remove_method :start; end
|
410
|
-
def self.start(ap_path = nil, main_context = nil, workspace = nil)
|
411
|
-
$0 = File::basename(ap_path, ".rb") if ap_path
|
412
|
-
|
413
|
-
# suppress some warnings about redefined constants
|
414
|
-
old_verbose, $VERBOSE = $VERBOSE, nil
|
415
|
-
IRB.setup(ap_path)
|
416
|
-
$VERBOSE = old_verbose
|
417
|
-
|
418
|
-
if @CONF[:SCRIPT] then
|
419
|
-
irb = Irb.new(main_context, @CONF[:SCRIPT])
|
420
|
-
else
|
421
|
-
irb = Irb.new(main_context)
|
422
|
-
end
|
423
|
-
|
424
|
-
if workspace then
|
425
|
-
irb.context.workspace = workspace
|
426
|
-
end
|
427
|
-
|
428
|
-
@CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
|
429
|
-
@CONF[:MAIN_CONTEXT] = irb.context
|
430
|
-
|
431
|
-
old_sigint = trap("SIGINT") do
|
432
|
-
begin
|
433
|
-
irb.signal_handle
|
434
|
-
rescue RubyLex::TerminateLineInput
|
435
|
-
# ignored
|
436
|
-
end
|
437
|
-
end
|
438
|
-
|
439
|
-
catch(:IRB_EXIT) do
|
440
|
-
irb.eval_input
|
441
|
-
end
|
442
|
-
ensure
|
443
|
-
trap("SIGINT", old_sigint)
|
444
|
-
end
|
445
|
-
|
446
|
-
class << self
|
447
|
-
alias :old_CurrentContext :CurrentContext
|
448
|
-
remove_method :CurrentContext
|
449
|
-
end
|
450
|
-
def IRB.CurrentContext
|
451
|
-
if old_CurrentContext.nil? and Breakpoint.use_drb? then
|
452
|
-
result = Object.new
|
453
|
-
def result.last_value; end
|
454
|
-
return result
|
455
|
-
else
|
456
|
-
old_CurrentContext
|
457
|
-
end
|
458
|
-
end
|
459
|
-
|
460
|
-
class Context
|
461
|
-
alias :old_evaluate :evaluate
|
462
|
-
def evaluate(line, line_no)
|
463
|
-
if line.chomp == "exit" then
|
464
|
-
exit
|
465
|
-
else
|
466
|
-
old_evaluate(line, line_no)
|
467
|
-
end
|
468
|
-
end
|
469
|
-
end
|
470
|
-
|
471
|
-
class WorkSpace
|
472
|
-
alias :old_evaluate :evaluate
|
473
|
-
|
474
|
-
def evaluate(*args)
|
475
|
-
if Breakpoint.use_drb? then
|
476
|
-
result = old_evaluate(*args)
|
477
|
-
if args[0] != :no_proxy and
|
478
|
-
not [true, false, nil].include?(result)
|
479
|
-
then
|
480
|
-
result.extend(DRbUndumped) rescue nil
|
481
|
-
end
|
482
|
-
return result
|
483
|
-
else
|
484
|
-
old_evaluate(*args)
|
485
|
-
end
|
486
|
-
end
|
487
|
-
end
|
488
|
-
|
489
|
-
module InputCompletor
|
490
|
-
def self.eval(code, context, *more)
|
491
|
-
# Big hack, this assumes that InputCompletor
|
492
|
-
# will only call eval() when it wants code
|
493
|
-
# to be executed in the IRB context.
|
494
|
-
IRB.conf[:MAIN_CONTEXT].workspace.evaluate(:no_proxy, code, *more)
|
495
|
-
end
|
496
|
-
end
|
497
|
-
end
|
498
|
-
|
499
|
-
module DRb # :nodoc:
|
500
|
-
class DRbObject
|
501
|
-
undef :inspect if method_defined?(:inspect)
|
502
|
-
undef :clone if method_defined?(:clone)
|
503
|
-
end
|
504
|
-
end
|
505
|
-
|
506
|
-
# See Breakpoint.breakpoint
|
507
|
-
def breakpoint(id = nil, &block)
|
508
|
-
Binding.of_caller do |context|
|
509
|
-
Breakpoint.breakpoint(id, context, &block)
|
510
|
-
end
|
511
|
-
end
|
512
|
-
|
513
|
-
# See Breakpoint.assert
|
514
|
-
def assert(&block)
|
515
|
-
Binding.of_caller do |context|
|
516
|
-
Breakpoint.assert(context, &block)
|
517
|
-
end
|
518
|
-
end
|