byebug 1.0.3 → 1.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.
- 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
|