byebug 1.0.3 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +13 -11
- data/Rakefile +0 -6
- data/bin/byebug +83 -136
- data/ext/byebug/byebug.c +182 -96
- data/ext/byebug/byebug.h +5 -7
- data/ext/byebug/context.c +52 -40
- data/lib/byebug.rb +81 -81
- data/lib/byebug/command.rb +18 -35
- data/lib/byebug/commands/control.rb +1 -1
- data/lib/byebug/commands/display.rb +0 -2
- data/lib/byebug/commands/enable.rb +4 -16
- data/lib/byebug/commands/eval.rb +5 -3
- data/lib/byebug/commands/frame.rb +68 -69
- data/lib/byebug/commands/help.rb +2 -1
- data/lib/byebug/commands/info.rb +43 -42
- data/lib/byebug/commands/method.rb +4 -3
- data/lib/byebug/commands/set.rb +10 -19
- data/lib/byebug/commands/show.rb +6 -13
- data/lib/byebug/interface.rb +1 -1
- data/lib/byebug/processor.rb +14 -17
- data/lib/byebug/version.rb +1 -2
- data/old_doc/byebug.texi +576 -847
- data/test/breakpoints_test.rb +0 -1
- data/test/conditions_test.rb +35 -33
- data/test/display_test.rb +14 -13
- data/test/edit_test.rb +28 -25
- data/test/eval_test.rb +0 -2
- data/test/finish_test.rb +4 -3
- data/test/frame_test.rb +20 -21
- data/test/help_test.rb +26 -23
- data/test/info_test.rb +105 -108
- data/test/irb_test.rb +26 -25
- data/test/kill_test.rb +19 -19
- data/test/list_test.rb +140 -156
- data/test/method_test.rb +21 -22
- data/test/post_mortem_test.rb +2 -5
- data/test/quit_test.rb +16 -17
- data/test/reload_test.rb +2 -2
- data/test/restart_test.rb +0 -1
- data/test/save_test.rb +31 -32
- data/test/set_test.rb +50 -47
- data/test/show_test.rb +67 -66
- data/test/source_test.rb +31 -34
- data/test/stepping_test.rb +32 -34
- data/test/support/test_dsl.rb +1 -1
- data/test/trace_test.rb +1 -2
- data/test/variables_test.rb +36 -34
- metadata +2 -4
- data/lib/byebug/commands/tmate.rb +0 -36
- data/test/tmate_test.rb +0 -44
data/ext/byebug/byebug.h
CHANGED
@@ -24,8 +24,6 @@ typedef struct rb_trace_arg_struct rb_trace_point_t;
|
|
24
24
|
#define CTX_FL_SET(c,f) do { (c)->flags |= (f); } while (0)
|
25
25
|
#define CTX_FL_UNSET(c,f) do { (c)->flags &= ~(f); } while (0)
|
26
26
|
|
27
|
-
#define IS_THREAD_ALIVE(t) (rb_funcall((t), idAlive, 0) == Qtrue)
|
28
|
-
|
29
27
|
/* types */
|
30
28
|
typedef enum {
|
31
29
|
CTX_STOP_NONE,
|
@@ -64,21 +62,21 @@ typedef struct {
|
|
64
62
|
|
65
63
|
/* functions */
|
66
64
|
extern VALUE Init_context(VALUE mByebug);
|
67
|
-
extern VALUE
|
65
|
+
extern VALUE Context_create(VALUE thread, VALUE cDebugThread);
|
66
|
+
extern VALUE Context_dup(debug_context_t *context);
|
68
67
|
extern void reset_stepping_stop_points(debug_context_t *context);
|
69
68
|
extern VALUE Context_ignored(VALUE self);
|
70
69
|
|
71
|
-
extern void push_frame(
|
70
|
+
extern void push_frame(debug_context_t *context, char* file, int lineno,
|
72
71
|
VALUE method_id, VALUE defined_class, VALUE binding,
|
73
72
|
VALUE self);
|
74
73
|
|
75
|
-
extern void pop_frame(
|
74
|
+
extern void pop_frame(debug_context_t *context);
|
76
75
|
|
77
|
-
extern void update_frame(
|
76
|
+
extern void update_frame(debug_frame_t *context, char* file, int lineno,
|
78
77
|
VALUE method_id, VALUE defined_class, VALUE binding,
|
79
78
|
VALUE self);
|
80
79
|
|
81
|
-
|
82
80
|
/* locked threads container */
|
83
81
|
typedef struct locked_thread_t {
|
84
82
|
VALUE thread;
|
data/ext/byebug/context.c
CHANGED
@@ -3,8 +3,6 @@
|
|
3
3
|
static VALUE cContext;
|
4
4
|
static int thnum_current = 0;
|
5
5
|
|
6
|
-
static VALUE idAlive;
|
7
|
-
|
8
6
|
static VALUE
|
9
7
|
id2ref(VALUE id)
|
10
8
|
{
|
@@ -45,9 +43,9 @@ delete_frame(debug_context_t *context)
|
|
45
43
|
xfree(frame);
|
46
44
|
}
|
47
45
|
|
48
|
-
|
49
|
-
|
50
|
-
|
46
|
+
extern void
|
47
|
+
update_frame(debug_frame_t *frame, char* file, int lineno, VALUE method_id,
|
48
|
+
VALUE defined_class, VALUE binding, VALUE self)
|
51
49
|
{
|
52
50
|
frame->file = file;
|
53
51
|
frame->line = lineno;
|
@@ -78,7 +76,7 @@ Context_dead(VALUE self)
|
|
78
76
|
{
|
79
77
|
debug_context_t *context;
|
80
78
|
Data_Get_Struct(self, debug_context_t, context);
|
81
|
-
return
|
79
|
+
return CTX_FL_TEST(context, CTX_FL_DEAD) ? Qtrue : Qfalse;
|
82
80
|
}
|
83
81
|
|
84
82
|
extern VALUE
|
@@ -92,54 +90,32 @@ Context_ignored(VALUE self)
|
|
92
90
|
}
|
93
91
|
|
94
92
|
extern void
|
95
|
-
push_frame(
|
93
|
+
push_frame(debug_context_t *context, char* file, int lineno, VALUE method_id,
|
96
94
|
VALUE defined_class, VALUE binding, VALUE self)
|
97
95
|
{
|
98
|
-
debug_context_t *context;
|
99
96
|
debug_frame_t *frame;
|
100
|
-
Data_Get_Struct(context_object, debug_context_t, context);
|
101
97
|
|
102
98
|
frame = ALLOC(debug_frame_t);
|
103
|
-
|
99
|
+
update_frame(frame, file, lineno, method_id, defined_class, binding, self);
|
104
100
|
frame->prev = context->stack;
|
105
101
|
context->stack = frame;
|
106
102
|
context->stack_size++;
|
107
103
|
}
|
108
104
|
|
109
105
|
extern void
|
110
|
-
pop_frame(
|
106
|
+
pop_frame(debug_context_t *context)
|
111
107
|
{
|
112
|
-
debug_context_t *context;
|
113
|
-
Data_Get_Struct(context_object, debug_context_t, context);
|
114
|
-
|
115
108
|
if (context->stack_size > 0) {
|
116
109
|
delete_frame(context);
|
117
110
|
}
|
118
111
|
}
|
119
112
|
|
120
|
-
extern void
|
121
|
-
update_frame(VALUE context_object, char* file, int lineno, VALUE method_id,
|
122
|
-
VALUE defined_class, VALUE binding, VALUE self)
|
123
|
-
{
|
124
|
-
debug_context_t *context;
|
125
|
-
Data_Get_Struct(context_object, debug_context_t, context);
|
126
|
-
|
127
|
-
if (context->stack_size == 0) {
|
128
|
-
push_frame(context_object, file, lineno, method_id, defined_class, binding,
|
129
|
-
self);
|
130
|
-
return;
|
131
|
-
}
|
132
|
-
fill_frame(context->stack, file, lineno, method_id, defined_class, binding,
|
133
|
-
self);
|
134
|
-
|
135
|
-
}
|
136
|
-
|
137
113
|
static void
|
138
114
|
Context_mark(debug_context_t *context)
|
139
115
|
{
|
140
116
|
debug_frame_t *frame;
|
141
117
|
|
142
|
-
|
118
|
+
//rb_gc_mark(context->thread);
|
143
119
|
frame = context->stack;
|
144
120
|
while (frame != NULL) {
|
145
121
|
rb_gc_mark(frame->self);
|
@@ -150,14 +126,14 @@ Context_mark(debug_context_t *context)
|
|
150
126
|
|
151
127
|
static void
|
152
128
|
Context_free(debug_context_t *context) {
|
153
|
-
while(context->stack_size > 0) {
|
129
|
+
while (context->stack_size > 0) {
|
154
130
|
delete_frame(context);
|
155
131
|
}
|
156
132
|
xfree(context);
|
157
133
|
}
|
158
134
|
|
159
135
|
extern VALUE
|
160
|
-
|
136
|
+
Context_create(VALUE thread, VALUE cDebugThread) {
|
161
137
|
debug_context_t *context;
|
162
138
|
|
163
139
|
context = ALLOC(debug_context_t);
|
@@ -174,6 +150,45 @@ context_create(VALUE thread, VALUE cDebugThread) {
|
|
174
150
|
return Data_Wrap_Struct(cContext, Context_mark, Context_free, context);
|
175
151
|
}
|
176
152
|
|
153
|
+
static void
|
154
|
+
frame_copy(debug_frame_t *new_frame, debug_frame_t *old_frame)
|
155
|
+
{
|
156
|
+
new_frame->file = old_frame->file;
|
157
|
+
new_frame->line = old_frame->line;
|
158
|
+
new_frame->method_id = old_frame->method_id;
|
159
|
+
new_frame->defined_class = old_frame->defined_class;
|
160
|
+
new_frame->binding = old_frame->binding;
|
161
|
+
new_frame->self = old_frame->self;
|
162
|
+
}
|
163
|
+
|
164
|
+
extern VALUE
|
165
|
+
Context_dup(debug_context_t *context)
|
166
|
+
{
|
167
|
+
debug_context_t *new_context;
|
168
|
+
debug_frame_t *source_frame = context->stack, *dest_frame, *new_frame;
|
169
|
+
|
170
|
+
new_context = ALLOC(debug_context_t);
|
171
|
+
memcpy(new_context, context, sizeof(debug_context_t));
|
172
|
+
new_context->dest_frame = -1;
|
173
|
+
new_context->stop_line = -1;
|
174
|
+
new_context->stop_frame = -1;
|
175
|
+
new_context->stop_next = -1;
|
176
|
+
new_context->stack_size = context->stack_size;
|
177
|
+
CTX_FL_SET(new_context, CTX_FL_DEAD);
|
178
|
+
new_context->stack = ALLOC(debug_frame_t);
|
179
|
+
frame_copy(new_context->stack, context->stack);
|
180
|
+
|
181
|
+
new_frame = new_context->stack;
|
182
|
+
while ((source_frame = source_frame->prev))
|
183
|
+
{
|
184
|
+
dest_frame = new_frame;
|
185
|
+
new_frame = ALLOC(debug_frame_t);
|
186
|
+
frame_copy(new_frame, source_frame);
|
187
|
+
dest_frame->prev = new_frame;
|
188
|
+
}
|
189
|
+
return Data_Wrap_Struct(cContext, 0, Context_free, new_context);
|
190
|
+
}
|
191
|
+
|
177
192
|
static debug_frame_t*
|
178
193
|
get_frame_no(debug_context_t *context, int frame_n)
|
179
194
|
{
|
@@ -329,7 +344,9 @@ Context_stop_reason(VALUE self)
|
|
329
344
|
|
330
345
|
Data_Get_Struct(self, debug_context_t, context);
|
331
346
|
|
332
|
-
|
347
|
+
if (CTX_FL_TEST(context, CTX_FL_DEAD))
|
348
|
+
symbol = "post-mortem";
|
349
|
+
else switch (context->stop_reason)
|
333
350
|
{
|
334
351
|
case CTX_STOP_STEP:
|
335
352
|
symbol = "step";
|
@@ -344,9 +361,6 @@ Context_stop_reason(VALUE self)
|
|
344
361
|
default:
|
345
362
|
symbol = "none";
|
346
363
|
}
|
347
|
-
if(CTX_FL_TEST(context, CTX_FL_DEAD))
|
348
|
-
symbol = "post-mortem";
|
349
|
-
|
350
364
|
return ID2SYM(rb_intern(symbol));
|
351
365
|
}
|
352
366
|
|
@@ -505,7 +519,5 @@ Init_context(VALUE mByebug)
|
|
505
519
|
rb_define_method(cContext, "step_over", Context_step_over, -1);
|
506
520
|
rb_define_method(cContext, "stop_frame=", Context_stop_frame, 1);
|
507
521
|
|
508
|
-
idAlive = rb_intern("alive?");
|
509
|
-
|
510
522
|
return cContext;
|
511
523
|
}
|
data/lib/byebug.rb
CHANGED
@@ -14,9 +14,9 @@ module Byebug
|
|
14
14
|
|
15
15
|
# Default options to Byebug.start
|
16
16
|
DEFAULT_START_SETTINGS = {
|
17
|
-
:
|
18
|
-
:
|
19
|
-
:
|
17
|
+
init: true, # Set $0 and save ARGV?
|
18
|
+
post_mortem: false, # post-mortem debugging on uncaught exception?
|
19
|
+
tracing: nil # Byebug.tracing? value. true/false resets
|
20
20
|
} unless defined?(DEFAULT_START_SETTINGS)
|
21
21
|
|
22
22
|
# Port number used for remote debugging
|
@@ -101,11 +101,11 @@ module Byebug
|
|
101
101
|
# If it's called without a block it returns +true+, unless byebug was
|
102
102
|
# already started.
|
103
103
|
#
|
104
|
-
# If a block is given, it starts byebug and yields block.
|
104
|
+
# If a block is given, it starts byebug and yields block. After the block is
|
105
105
|
# executed it stops byebug with Byebug.stop method. Inside the block you
|
106
106
|
# will probably want to have a call to Byebug.byebug. For example:
|
107
107
|
#
|
108
|
-
# Byebug.start{byebug; foo} # Stop inside of foo
|
108
|
+
# Byebug.start { byebug; foo } # Stop inside of foo
|
109
109
|
#
|
110
110
|
# Also, byebug only allows one invocation of byebug at a time; nested
|
111
111
|
# Byebug.start's have no effect and you can't use this inside byebug itself.
|
@@ -131,14 +131,15 @@ module Byebug
|
|
131
131
|
Byebug.const_set('INITIAL_DIR', Dir.pwd) unless defined? Byebug::INITIAL_DIR
|
132
132
|
end
|
133
133
|
Byebug.tracing = options[:tracing] unless options[:tracing].nil?
|
134
|
+
Byebug.start_sentinal=caller(0)[1]
|
134
135
|
if Byebug.started?
|
135
136
|
retval = block && block.call(self)
|
136
137
|
else
|
137
138
|
retval = Byebug._start(&block)
|
138
139
|
end
|
139
|
-
|
140
|
-
|
141
|
-
|
140
|
+
if options[:post_mortem]
|
141
|
+
post_mortem
|
142
|
+
end
|
142
143
|
return retval
|
143
144
|
end
|
144
145
|
|
@@ -254,62 +255,62 @@ module Byebug
|
|
254
255
|
processor.process_commands(verbose)
|
255
256
|
end
|
256
257
|
|
257
|
-
|
258
|
-
|
259
|
-
#
|
260
|
-
#
|
261
|
-
#
|
262
|
-
#
|
263
|
-
#
|
264
|
-
#
|
265
|
-
#
|
266
|
-
#
|
267
|
-
#
|
268
|
-
#
|
269
|
-
#
|
270
|
-
#
|
271
|
-
#
|
272
|
-
#
|
273
|
-
# # end
|
274
|
-
# # Byebug.post_mortem do
|
275
|
-
# # ...
|
276
|
-
# # offender
|
277
|
-
# # ...
|
278
|
-
# # end
|
279
|
-
# def post_mortem
|
280
|
-
# if block_given?
|
281
|
-
# old_post_mortem = self.post_mortem?
|
282
|
-
# begin
|
283
|
-
# self.post_mortem = true
|
284
|
-
# yield
|
285
|
-
# rescue Exception => exp
|
286
|
-
# handle_post_mortem(exp)
|
287
|
-
# raise
|
288
|
-
# ensure
|
289
|
-
# self.post_mortem = old_post_mortem
|
290
|
-
# end
|
291
|
-
# else
|
292
|
-
# return if post_mortem?
|
293
|
-
# self.post_mortem = true
|
294
|
-
# debug_at_exit do
|
295
|
-
# handle_post_mortem($!) if $! && post_mortem?
|
296
|
-
# end
|
297
|
-
# end
|
258
|
+
##
|
259
|
+
# Activates the post-mortem mode. There are two ways of using it:
|
260
|
+
#
|
261
|
+
# == Global post-mortem mode
|
262
|
+
# By calling Byebug.post_mortem method without a block, you install an
|
263
|
+
# at_exit hook that intercepts any exception not handled by your script
|
264
|
+
# and enables post-mortem mode.
|
265
|
+
#
|
266
|
+
# == Local post-mortem mode
|
267
|
+
#
|
268
|
+
# If you know that a particular block of code raises an exception you can
|
269
|
+
# enable post-mortem mode by wrapping this block with Byebug.post_mortem,
|
270
|
+
# e.g.
|
271
|
+
#
|
272
|
+
# def offender
|
273
|
+
# raise 'error'
|
298
274
|
# end
|
299
|
-
|
300
|
-
#
|
301
|
-
#
|
302
|
-
#
|
303
|
-
# Byebug.suspend
|
304
|
-
# orig_tracing = Byebug.tracing, Byebug.current_context.tracing
|
305
|
-
# Byebug.tracing = Byebug.current_context.tracing = false
|
306
|
-
# Byebug.last_exception = exp
|
307
|
-
# handler.at_line(exp.__debug_context, exp.__debug_file, exp.__debug_line)
|
308
|
-
# ensure
|
309
|
-
# Byebug.tracing, Byebug.current_context.tracing = orig_tracing
|
310
|
-
# Byebug.resume
|
275
|
+
# Byebug.post_mortem do
|
276
|
+
# ...
|
277
|
+
# offender
|
278
|
+
# ...
|
311
279
|
# end
|
312
|
-
|
280
|
+
def post_mortem
|
281
|
+
if block_given?
|
282
|
+
old_post_mortem = self.post_mortem?
|
283
|
+
begin
|
284
|
+
self.post_mortem = true
|
285
|
+
yield
|
286
|
+
rescue Exception => exp
|
287
|
+
handle_post_mortem(exp)
|
288
|
+
raise
|
289
|
+
ensure
|
290
|
+
self.post_mortem = old_post_mortem
|
291
|
+
end
|
292
|
+
else
|
293
|
+
return if self.post_mortem?
|
294
|
+
self.post_mortem = true
|
295
|
+
debug_at_exit do
|
296
|
+
handle_post_mortem($!) if $! && post_mortem?
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
def handle_post_mortem(exp)
|
302
|
+
return if !exp || !exp.__debug_context ||
|
303
|
+
exp.__debug_context.stack_size == 0
|
304
|
+
#Byebug.suspend
|
305
|
+
orig_tracing = Byebug.tracing?, Byebug.current_context.tracing
|
306
|
+
Byebug.tracing = Byebug.current_context.tracing = false
|
307
|
+
Byebug.last_exception = exp
|
308
|
+
handler.at_line(exp.__debug_context, exp.__debug_file, exp.__debug_line)
|
309
|
+
ensure
|
310
|
+
Byebug.tracing, Byebug.current_context.tracing = orig_tracing
|
311
|
+
#Byebug.resume
|
312
|
+
end
|
313
|
+
private :handle_post_mortem
|
313
314
|
|
314
315
|
end
|
315
316
|
|
@@ -321,7 +322,7 @@ module Byebug
|
|
321
322
|
|
322
323
|
end
|
323
324
|
|
324
|
-
class Exception
|
325
|
+
class Exception
|
325
326
|
attr_reader :__debug_file, :__debug_line, :__debug_binding, :__debug_context
|
326
327
|
end
|
327
328
|
|
@@ -343,24 +344,23 @@ class Module
|
|
343
344
|
EOD
|
344
345
|
end
|
345
346
|
|
346
|
-
#
|
347
|
-
#
|
348
|
-
#
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
# end
|
347
|
+
#
|
348
|
+
# Wraps the +meth+ method with Byebug.post_mortem {...} block.
|
349
|
+
#
|
350
|
+
def post_mortem_method(meth)
|
351
|
+
old_meth = "__postmortem_#{meth}"
|
352
|
+
old_meth = "#{$1}_set" if old_meth =~ /^(.+)=$/
|
353
|
+
alias_method old_meth.to_sym, meth
|
354
|
+
class_eval <<-EOD
|
355
|
+
def #{meth}(*args, &block)
|
356
|
+
Byebug.start do |dbg|
|
357
|
+
dbg.post_mortem do
|
358
|
+
#{old_meth}(*args, &block)
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
EOD
|
363
|
+
end
|
364
364
|
end
|
365
365
|
|
366
366
|
module Kernel
|
data/lib/byebug/command.rb
CHANGED
@@ -20,24 +20,23 @@ module Byebug
|
|
20
20
|
defined?(BYEBUG_DIR)
|
21
21
|
|
22
22
|
class Command
|
23
|
-
|
24
23
|
SubcmdStruct = Struct.new(:name, :min, :short_help, :long_help) unless
|
25
24
|
defined?(SubcmdStruct)
|
26
25
|
|
27
26
|
##
|
28
27
|
# Print list of subcmds
|
29
28
|
#
|
30
|
-
def
|
29
|
+
def format_subcmds(subcmds)
|
31
30
|
cmd_name = self.class.name[/Byebug::(.*)Command/, 1].downcase
|
32
|
-
|
33
|
-
|
31
|
+
s = "\n" \
|
32
|
+
"--\n" \
|
33
|
+
"List of \"#{cmd_name}\" subcommands:\n" \
|
34
|
+
"--\n"
|
34
35
|
for subcmd in subcmds do
|
35
|
-
|
36
|
+
s += "#{cmd_name} #{subcmd.name} -- #{subcmd.short_help}\n"
|
36
37
|
end
|
37
38
|
end
|
38
39
|
|
39
|
-
include Columnize
|
40
|
-
|
41
40
|
##
|
42
41
|
# Find param in subcmds.
|
43
42
|
#
|
@@ -60,14 +59,12 @@ module Byebug
|
|
60
59
|
@commands ||= []
|
61
60
|
end
|
62
61
|
|
63
|
-
DEF_OPTIONS = {
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
:need_context => false,
|
70
|
-
} unless defined?(DEF_OPTIONS)
|
62
|
+
DEF_OPTIONS = { allow_in_control: false,
|
63
|
+
allow_in_post_mortem: true ,
|
64
|
+
event: true ,
|
65
|
+
always_run: 0 ,
|
66
|
+
unknown: false,
|
67
|
+
need_context: false } unless defined?(DEF_OPTIONS)
|
71
68
|
|
72
69
|
def inherited(klass)
|
73
70
|
DEF_OPTIONS.each do |o, v|
|
@@ -109,28 +106,14 @@ module Byebug
|
|
109
106
|
@settings = Object.new
|
110
107
|
map = settings_map
|
111
108
|
c = class << @settings; self end
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
map[name][:getter].call
|
116
|
-
end
|
117
|
-
else
|
118
|
-
c.send(:define_method, :[]) do |name|
|
119
|
-
raise "No such setting #{name}" unless map.has_key?(name)
|
120
|
-
map[name][:getter].call
|
121
|
-
end
|
109
|
+
c.send(:define_method, :[]) do |name|
|
110
|
+
raise "No such setting #{name}" unless map.has_key?(name)
|
111
|
+
map[name][:getter].call
|
122
112
|
end
|
123
113
|
c = class << @settings; self end
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
map[name][:setter].call(value)
|
128
|
-
end
|
129
|
-
else
|
130
|
-
c.send(:define_method, :[]=) do |name, value|
|
131
|
-
raise "No such setting #{name}" unless map.has_key?(name)
|
132
|
-
map[name][:setter].call(value)
|
133
|
-
end
|
114
|
+
c.send(:define_method, :[]=) do |name, value|
|
115
|
+
raise "No such setting #{name}" unless map.has_key?(name)
|
116
|
+
map[name][:setter].call(value)
|
134
117
|
end
|
135
118
|
end
|
136
119
|
@settings
|