therubyracer-freebsd 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. data/.gitignore +13 -0
  2. data/.rspec +1 -0
  3. data/.travis.yml +8 -0
  4. data/.yardopts +1 -0
  5. data/Changelog.md +231 -0
  6. data/Gemfile +3 -0
  7. data/README.md +167 -0
  8. data/Rakefile +26 -0
  9. data/bin/therubyracer +11 -0
  10. data/ext/v8/extconf.rb +26 -0
  11. data/ext/v8/rr.cpp +189 -0
  12. data/ext/v8/rr.h +41 -0
  13. data/ext/v8/v8.cpp +48 -0
  14. data/ext/v8/v8_array.cpp +48 -0
  15. data/ext/v8/v8_array.h +8 -0
  16. data/ext/v8/v8_callbacks.cpp +81 -0
  17. data/ext/v8/v8_callbacks.h +8 -0
  18. data/ext/v8/v8_context.cpp +92 -0
  19. data/ext/v8/v8_context.h +6 -0
  20. data/ext/v8/v8_date.cpp +40 -0
  21. data/ext/v8/v8_date.h +6 -0
  22. data/ext/v8/v8_debug.cpp +17 -0
  23. data/ext/v8/v8_debug.h +6 -0
  24. data/ext/v8/v8_exception.cpp +133 -0
  25. data/ext/v8/v8_exception.h +11 -0
  26. data/ext/v8/v8_external.cpp +70 -0
  27. data/ext/v8/v8_external.h +8 -0
  28. data/ext/v8/v8_function.cpp +69 -0
  29. data/ext/v8/v8_function.h +11 -0
  30. data/ext/v8/v8_handle.cpp +186 -0
  31. data/ext/v8/v8_handle.h +48 -0
  32. data/ext/v8/v8_locker.cpp +139 -0
  33. data/ext/v8/v8_locker.h +6 -0
  34. data/ext/v8/v8_message.cpp +67 -0
  35. data/ext/v8/v8_message.h +10 -0
  36. data/ext/v8/v8_object.cpp +122 -0
  37. data/ext/v8/v8_object.h +10 -0
  38. data/ext/v8/v8_script.cpp +36 -0
  39. data/ext/v8/v8_script.h +8 -0
  40. data/ext/v8/v8_string.cpp +52 -0
  41. data/ext/v8/v8_string.h +9 -0
  42. data/ext/v8/v8_template.cpp +344 -0
  43. data/ext/v8/v8_template.h +8 -0
  44. data/ext/v8/v8_try_catch.cpp +70 -0
  45. data/ext/v8/v8_try_catch.h +5 -0
  46. data/ext/v8/v8_v8.cpp +34 -0
  47. data/ext/v8/v8_v8.h +6 -0
  48. data/ext/v8/v8_value.cpp +175 -0
  49. data/ext/v8/v8_value.h +10 -0
  50. data/ext/v8/v8_weakref.cpp +61 -0
  51. data/ext/v8/v8_weakref.h +29 -0
  52. data/lib/v8.rb +23 -0
  53. data/lib/v8/access.rb +92 -0
  54. data/lib/v8/array.rb +17 -0
  55. data/lib/v8/c/locker.rb +18 -0
  56. data/lib/v8/cli.rb +133 -0
  57. data/lib/v8/context.rb +111 -0
  58. data/lib/v8/error.rb +130 -0
  59. data/lib/v8/function.rb +44 -0
  60. data/lib/v8/object.rb +69 -0
  61. data/lib/v8/portal.rb +86 -0
  62. data/lib/v8/portal/caller.rb +37 -0
  63. data/lib/v8/portal/constructor.rb +98 -0
  64. data/lib/v8/portal/function.rb +63 -0
  65. data/lib/v8/portal/interceptors.rb +152 -0
  66. data/lib/v8/portal/proxies.rb +151 -0
  67. data/lib/v8/portal/templates.rb +73 -0
  68. data/lib/v8/stack.rb +66 -0
  69. data/lib/v8/tap.rb +9 -0
  70. data/lib/v8/version.rb +3 -0
  71. data/spec/ext/array_spec.rb +15 -0
  72. data/spec/ext/cxt_spec.rb +57 -0
  73. data/spec/ext/ext_spec_helper.rb +27 -0
  74. data/spec/ext/func_spec.rb +64 -0
  75. data/spec/ext/object_spec.rb +10 -0
  76. data/spec/ext/string_spec.rb +11 -0
  77. data/spec/ext/try_catch_spec.rb +60 -0
  78. data/spec/redjs_spec.rb +9 -0
  79. data/spec/spec_helper.rb +9 -0
  80. data/spec/v8/error_spec.rb +131 -0
  81. data/spec/v8/portal/proxies_spec.rb +106 -0
  82. data/specmem/handle_memspec.rb +41 -0
  83. data/specmem/object_memspec.rb +14 -0
  84. data/specmem/proxies_memspec.rb +49 -0
  85. data/specmem/spec_helper.rb +24 -0
  86. data/specthread/spec_helper.rb +2 -0
  87. data/specthread/threading_spec.rb +13 -0
  88. data/thefrontside.png +0 -0
  89. data/therubyracer.gemspec +27 -0
  90. metadata +183 -0
@@ -0,0 +1,8 @@
1
+ #ifndef _RUBY_V8_TEMPLATE_
2
+ #define _RUBY_V8_TEMPLATE_
3
+
4
+ #include "rr.h"
5
+
6
+ void rr_init_template();
7
+
8
+ #endif
@@ -0,0 +1,70 @@
1
+ #include "rr.h"
2
+ #include "v8_try_catch.h"
3
+ #include "v8_message.h"
4
+
5
+ using namespace v8;
6
+
7
+ namespace {
8
+ VALUE TryCatchClass;
9
+
10
+ TryCatch *unwrap(VALUE self) {
11
+ TryCatch *tc = 0;
12
+ Data_Get_Struct(self, class TryCatch, tc);
13
+ if (RTEST(rb_iv_get(self, "dead"))) {
14
+ rb_raise(rb_eScriptError, "out of scope access of %s", RSTRING_PTR(rb_inspect(self)));
15
+ return false;
16
+ } else {
17
+ return tc;
18
+ }
19
+ }
20
+
21
+ VALUE Try(int argc, VALUE *argv, VALUE self) {
22
+ if (rb_block_given_p()) {
23
+ HandleScope scope;
24
+ TryCatch tc;
25
+ VALUE try_catch = Data_Wrap_Struct(TryCatchClass, 0, 0, &tc);
26
+ rb_iv_set(try_catch, "dead", Qfalse);
27
+ VALUE result = rb_yield(try_catch);
28
+ rb_iv_set(try_catch, "dead", Qtrue);
29
+ tc.Reset();
30
+ return result;
31
+ } else {
32
+ return Qnil;
33
+ }
34
+ }
35
+
36
+ VALUE HasCaught(VALUE self) {
37
+ TryCatch *tc = unwrap(self);
38
+ return tc ? rr_v82rb(tc->HasCaught()) : Qnil;
39
+ }
40
+
41
+ VALUE _Exception(VALUE self) {
42
+ TryCatch *tc = unwrap(self);
43
+ return tc ? rr_v82rb(tc->Exception()) : Qnil;
44
+ }
45
+
46
+ VALUE _StackTrace(VALUE self) {
47
+ TryCatch *tc = unwrap(self);
48
+ return tc ? rr_v82rb(tc->StackTrace()) : Qnil;
49
+ }
50
+
51
+ VALUE _Message(VALUE self) {
52
+ TryCatch *tc = unwrap(self);
53
+ return tc ? rr_v82rb(tc->Message()) : Qnil;
54
+ }
55
+
56
+ VALUE CanContinue(VALUE self) {
57
+ TryCatch *tc = unwrap(self);
58
+ return tc ? rr_v82rb(tc->CanContinue()) : Qnil;
59
+ }
60
+ }
61
+
62
+ void rr_init_v8_try_catch() {
63
+ TryCatchClass = rr_define_class("TryCatch");
64
+ rr_define_singleton_method(TryCatchClass, "try", Try, -1);
65
+ rr_define_method(TryCatchClass, "HasCaught", HasCaught, 0);
66
+ rr_define_method(TryCatchClass, "Exception", _Exception, 0);
67
+ rr_define_method(TryCatchClass, "StackTrace", _StackTrace, 0);
68
+ rr_define_method(TryCatchClass, "Message", _Message, 0);
69
+ rr_define_method(TryCatchClass, "CanContinue", CanContinue, 0);
70
+ }
@@ -0,0 +1,5 @@
1
+ #ifndef _RR_V8_TRY_CATCH_
2
+ #define _RR_V8_TRY_CATCH_
3
+
4
+ void rr_init_v8_try_catch();
5
+ #endif
@@ -0,0 +1,34 @@
1
+
2
+ #include "rr.h"
3
+
4
+ using namespace v8;
5
+
6
+ namespace {
7
+
8
+ VALUE IsDead(VALUE self) {
9
+ return rr_v82rb(V8::IsDead());
10
+ }
11
+
12
+ VALUE AdjustAmountOfExternalAllocatedMemory(VALUE self, VALUE bytes) {
13
+ V8::AdjustAmountOfExternalAllocatedMemory(NUM2INT(bytes));
14
+ return Qnil;
15
+ }
16
+
17
+ VALUE IdleNotification(VALUE self) {
18
+ return rr_v82rb(V8::IdleNotification());
19
+ }
20
+
21
+ VALUE SetFlagsFromString(VALUE self, VALUE string) {
22
+ V8::SetFlagsFromString(RSTRING_PTR(string), (int)RSTRING_LEN(string));
23
+ return Qnil;
24
+ }
25
+ }
26
+
27
+
28
+ void rr_init_v8_v8() {
29
+ VALUE V8Module = rr_define_module("V8");
30
+ rr_define_singleton_method(V8Module, "IsDead", IsDead, 0);
31
+ rr_define_singleton_method(V8Module, "AdjustAmountOfExternalAllocatedMemory", AdjustAmountOfExternalAllocatedMemory, 1);
32
+ rr_define_singleton_method(V8Module, "IdleNotification", IdleNotification, 0);
33
+ rr_define_singleton_method(V8Module, "SetFlagsFromString", SetFlagsFromString, 1);
34
+ }
@@ -0,0 +1,6 @@
1
+ #ifndef _RR_V8_V8_
2
+ #define _RR_V8_V8_
3
+
4
+ void rr_init_v8_v8();
5
+
6
+ #endif
@@ -0,0 +1,175 @@
1
+ #include "v8_handle.h"
2
+ #include "v8_value.h"
3
+
4
+ using namespace v8;
5
+ namespace {
6
+
7
+ VALUE ValueClass;
8
+
9
+ Persistent<Value>& unwrap(VALUE value) {
10
+ return rr_v8_handle<Value>(value);
11
+ }
12
+ VALUE IsEmpty(VALUE value) {
13
+ return value == rr_v8_value_empty() ? Qtrue : Qfalse;
14
+ }
15
+ VALUE IsUndefined(VALUE self) {
16
+ HandleScope scope;
17
+ return rr_v82rb(unwrap(self)->IsUndefined());
18
+ }
19
+ VALUE IsNull(VALUE self) {
20
+ HandleScope scope;
21
+ return rr_v82rb(unwrap(self)->IsNull());
22
+ }
23
+ VALUE IsTrue(VALUE self) {
24
+ HandleScope scope;
25
+ return rr_v82rb(unwrap(self)->IsTrue());
26
+ }
27
+ VALUE IsFalse(VALUE self) {
28
+ HandleScope scope;
29
+ return rr_v82rb(unwrap(self)->IsFalse());
30
+ }
31
+ VALUE IsString(VALUE self) {
32
+ HandleScope scope;
33
+ return rr_v82rb(unwrap(self)->IsString());
34
+ }
35
+ VALUE IsFunction(VALUE self) {
36
+ HandleScope scope;
37
+ return rr_v82rb(unwrap(self)->IsFunction());
38
+ }
39
+ VALUE IsArray(VALUE self) {
40
+ HandleScope scope;
41
+ return rr_v82rb(unwrap(self)->IsArray());
42
+ }
43
+ VALUE IsObject(VALUE self) {
44
+ HandleScope scope;
45
+ return rr_v82rb(unwrap(self)->IsObject());
46
+ }
47
+ VALUE IsBoolean(VALUE self) {
48
+ HandleScope scope;
49
+ return rr_v82rb(unwrap(self)->IsBoolean());
50
+ }
51
+ VALUE IsNumber(VALUE self) {
52
+ HandleScope scope;
53
+ return rr_v82rb(unwrap(self)->IsNumber());
54
+ }
55
+ VALUE IsExternal(VALUE self) {
56
+ HandleScope scope;
57
+ return rr_v82rb(unwrap(self)->IsExternal());
58
+ }
59
+ VALUE IsInt32(VALUE self) {
60
+ HandleScope scope;
61
+ return rr_v82rb(unwrap(self)->IsInt32());
62
+ }
63
+ VALUE IsUint32(VALUE self) {
64
+ HandleScope scope;
65
+ return rr_v82rb(unwrap(self)->IsUint32());
66
+ }
67
+ VALUE IsDate(VALUE self) {
68
+ HandleScope scope;
69
+ return rr_v82rb(unwrap(self)->IsDate());
70
+ }
71
+
72
+ VALUE ToBoolean(VALUE self) {
73
+ HandleScope scope;
74
+ return rr_v82rb(unwrap(self)->ToBoolean());
75
+ }
76
+ VALUE ToNumber(VALUE self) {
77
+ HandleScope scope;
78
+ return rr_v82rb(unwrap(self)->ToNumber());
79
+ }
80
+ VALUE ToString(VALUE self) {
81
+ HandleScope scope;
82
+ return rr_v82rb(unwrap(self)->ToString());
83
+ }
84
+ VALUE ToDetailString(VALUE self) {
85
+ HandleScope scope;
86
+ return rr_v82rb(unwrap(self)->ToDetailString());
87
+ }
88
+ VALUE ToObject(VALUE self) {
89
+ HandleScope scope;
90
+ return rr_v82rb(unwrap(self)->ToObject());
91
+ }
92
+ VALUE ToInteger(VALUE self) {
93
+ HandleScope scope;
94
+ return rr_v82rb(unwrap(self)->ToInteger());
95
+ }
96
+ VALUE ToUint32(VALUE self) {
97
+ HandleScope scope;
98
+ return rr_v82rb(unwrap(self)->ToUint32());
99
+ }
100
+ VALUE ToInt32(VALUE self) {
101
+ HandleScope scope;
102
+ return rr_v82rb(unwrap(self)->ToInt32());
103
+ }
104
+ VALUE ToArrayIndex(VALUE self) {
105
+ HandleScope scope;
106
+ return rr_v82rb(unwrap(self)->ToArrayIndex());
107
+ }
108
+
109
+ VALUE Equals(VALUE self, VALUE that) {
110
+ HandleScope scope;
111
+ return rr_v82rb(unwrap(self)->Equals(unwrap(that)));
112
+ }
113
+ VALUE StrictEquals(VALUE self, VALUE that) {
114
+ HandleScope scope;
115
+ return rr_v82rb(unwrap(self)->StrictEquals(unwrap(that)));
116
+ }
117
+
118
+ VALUE BooleanValue(VALUE self) {
119
+ HandleScope scope;
120
+ return rr_v82rb(unwrap(self)->BooleanValue());
121
+ }
122
+
123
+ VALUE NumberValue(VALUE self) {
124
+ HandleScope scope;
125
+ return rr_v82rb(unwrap(self)->NumberValue());
126
+ }
127
+ }
128
+
129
+ VALUE rr_v8_value_class() {
130
+ return ValueClass;
131
+ }
132
+
133
+ VALUE rr_v8_value_empty() {
134
+ return rr_const_get("Empty");
135
+ }
136
+
137
+ void rr_init_value() {
138
+ ValueClass = rr_define_class("Value", rr_v8_handle_class());
139
+ rr_define_const("Empty", rr_v8_handle_new(ValueClass, Handle<Value>()));
140
+
141
+ rr_define_method(ValueClass, "IsEmpty", IsEmpty, 0);
142
+ rr_define_method(ValueClass, "IsUndefined", IsUndefined, 0);
143
+ rr_define_method(ValueClass, "IsNull", IsNull, 0);
144
+ rr_define_method(ValueClass, "IsTrue", IsTrue, 0);
145
+ rr_define_method(ValueClass, "IsFalse", IsFalse, 0);
146
+ rr_define_method(ValueClass, "IsString", IsString, 0);
147
+ rr_define_method(ValueClass, "IsFunction", IsFunction, 0);
148
+ rr_define_method(ValueClass, "IsArray", IsArray, 0);
149
+ rr_define_method(ValueClass, "IsObject", IsObject, 0);
150
+ rr_define_method(ValueClass, "IsBoolean", IsBoolean, 0);
151
+ rr_define_method(ValueClass, "IsNumber", IsNumber, 0);
152
+ rr_define_method(ValueClass, "IsExternal", IsExternal, 0);
153
+ rr_define_method(ValueClass, "IsInt32", IsInt32, 0);
154
+ rr_define_method(ValueClass, "IsUint32", IsUint32, 0);
155
+ rr_define_method(ValueClass, "IsDate", IsDate, 0);
156
+
157
+ rr_define_method(ValueClass, "ToBoolean", ToBoolean, 0);
158
+ rr_define_method(ValueClass, "ToNumber", ToNumber, 0);
159
+ rr_define_method(ValueClass, "ToString", ToString, 0);
160
+ rr_define_method(ValueClass, "ToDetailString", ToDetailString, 0);
161
+ rr_define_method(ValueClass, "ToObject", ToObject, 0);
162
+ rr_define_method(ValueClass, "ToInteger", ToInteger, 0);
163
+ rr_define_method(ValueClass, "ToUint32", ToUint32, 0);
164
+ rr_define_method(ValueClass, "ToArrayIndex", ToArrayIndex, 0);
165
+
166
+ rr_define_method(ValueClass, "Equals", Equals, 1);
167
+ rr_define_method(ValueClass, "StrictEquals", StrictEquals, 1);
168
+
169
+ rr_define_method(ValueClass, "BooleanValue", BooleanValue, 0);
170
+ rr_define_method(ValueClass, "NumberValue", NumberValue, 0);
171
+ }
172
+
173
+ VALUE rr_wrap_v8_value(Handle<Value>& value) {
174
+ return rr_v8_handle_new(ValueClass, value);
175
+ }
@@ -0,0 +1,10 @@
1
+ #ifndef _RR_V8_VALUE_
2
+ #define _RR_V8_VALUE_
3
+
4
+ #include "rr.h"
5
+
6
+ void rr_init_value();
7
+ VALUE rr_wrap_v8_value(v8::Handle<v8::Value>& value);
8
+ VALUE rr_v8_value_class();
9
+ VALUE rr_v8_value_empty();
10
+ #endif
@@ -0,0 +1,61 @@
1
+ #include "v8.h"
2
+ #include "v8_weakref.h"
3
+
4
+ using namespace v8;
5
+
6
+ v8_weakref::v8_weakref(VALUE object) {
7
+ this->v8_active = true;
8
+ this->rb_active = true;
9
+ this->external = Persistent<External>::New(External::New((void *)this));
10
+ this->external.MakeWeak(this, v8_weakref_dispose);
11
+ this->set(object);
12
+ }
13
+
14
+ void v8_weakref::set(VALUE value) {
15
+ this->object_id = rb_obj_id(value);
16
+ this->rb_active = true;
17
+ VALUE data = Data_Wrap_Struct(rb_cObject, 0, 0, this);
18
+ rr_define_finalizer(value,(void*)v8_weakref_finalize, data);
19
+ }
20
+
21
+ VALUE v8_weakref::get() {
22
+ if (this->object_id) {
23
+ return rb_rescue((VALUE (*)(...))v8_weakref_id2ref, this->object_id, (VALUE (*)(...))v8_weakref_nil, Qnil);
24
+ } else {
25
+ return Qnil;
26
+ }
27
+ }
28
+
29
+ VALUE v8_weakref_finalize(VALUE object_id, VALUE data) {
30
+ v8_weakref* weakref = 0;
31
+ Data_Get_Struct(data, struct v8_weakref, weakref);
32
+ weakref->object_id = Qnil;
33
+ weakref->rb_active = false;
34
+ if (!weakref->v8_active) {
35
+ delete weakref;
36
+ }
37
+ return Qnil;
38
+ }
39
+
40
+ void v8_weakref_dispose(Persistent<Value> value, void* data) {
41
+ value.Dispose();
42
+ value.Clear();
43
+ v8_weakref* weakref = (v8_weakref*)data;
44
+ weakref->v8_active = false;
45
+ if (!weakref->rb_active) {
46
+ delete weakref;
47
+ }
48
+ }
49
+
50
+ VALUE v8_weakref_nil(VALUE nil, VALUE exception) {
51
+ return nil;
52
+ }
53
+
54
+ VALUE v8_weakref_objectspace() {
55
+ return rb_const_get(rb_cObject, rb_intern("ObjectSpace"));
56
+ }
57
+
58
+ VALUE v8_weakref_id2ref(VALUE id) {
59
+ return rb_funcall(v8_weakref_objectspace(), rb_intern("_id2ref"), 1, id);
60
+ }
61
+
@@ -0,0 +1,29 @@
1
+ #ifndef _RR_V8_WEAKREF_
2
+ #define _RR_V8_WEAKREF_
3
+
4
+ #include <v8.h>
5
+ #include "ruby.h"
6
+ #include "rr.h"
7
+
8
+ struct v8_weakref {
9
+ v8_weakref(VALUE object);
10
+ VALUE get();
11
+ void set(VALUE object);
12
+ void retain();
13
+ void release();
14
+
15
+ VALUE object_id;
16
+ bool v8_active;
17
+ bool rb_active;
18
+ v8::Persistent<v8::External> external;
19
+ };
20
+
21
+ void v8_weakref_dispose(v8::Persistent<v8::Value> value, void* weakref);
22
+ VALUE v8_weakref_finalize(VALUE self, VALUE object_id);
23
+ VALUE v8_weakref_objectspace();
24
+ VALUE v8_weakref_nil(VALUE nil, VALUE exception);
25
+ VALUE v8_weakref_id2ref(VALUE id);
26
+
27
+ // extern "C" VALUE rb_proc_new(VALUE (*)(ANYARGS/* VALUE yieldarg[, VALUE procarg] */), VALUE);
28
+
29
+ #endif
@@ -0,0 +1,23 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ module V8
5
+ require 'v8/version'
6
+ require 'v8/v8' #native glue
7
+ require 'v8/c/locker'
8
+ require 'v8/portal'
9
+ require 'v8/portal/caller'
10
+ require 'v8/portal/proxies'
11
+ require 'v8/portal/templates'
12
+ require 'v8/portal/function'
13
+ require 'v8/portal/constructor'
14
+ require 'v8/portal/interceptors'
15
+ require 'v8/context'
16
+ require 'v8/object'
17
+ require 'v8/array'
18
+ require 'v8/function'
19
+ require 'v8/tap'
20
+ require 'v8/access'
21
+ require 'v8/error'
22
+ require 'v8/stack'
23
+ end
@@ -0,0 +1,92 @@
1
+ require 'set'
2
+ module V8
3
+ class Access
4
+ def get(obj, name, &dontintercept)
5
+ methods = accessible_methods(obj)
6
+ if methods.include?(name)
7
+ method = obj.method(name)
8
+ method.arity == 0 ? method.call : method.unbind
9
+ elsif obj.respond_to?(:[]) && !special?(name)
10
+ obj.send(:[], name, &dontintercept)
11
+ else
12
+ yield
13
+ end
14
+ end
15
+
16
+ def iget(obj, index, &dontintercept)
17
+ if obj.respond_to?(:[])
18
+ obj.send(:[], index, &dontintercept)
19
+ else
20
+ yield
21
+ end
22
+ end
23
+
24
+ def set(obj, name, value, &dontintercept)
25
+ setter = name + "="
26
+ methods = accessible_methods(obj, true)
27
+ if methods.include?(setter)
28
+ obj.send(setter, value)
29
+ elsif obj.respond_to?(:[]=) && !special?(name)
30
+ obj.send(:[]=, name, value, &dontintercept)
31
+ else
32
+ yield
33
+ end
34
+ end
35
+
36
+ def iset(obj, index, value, &dontintercept)
37
+ if obj.respond_to?(:[]=)
38
+ obj.send(:[]=, index, value, &dontintercept)
39
+ else
40
+ yield
41
+ end
42
+ end
43
+
44
+ def query(obj, name, attributes)
45
+ if obj.respond_to?(name)
46
+ attributes.dont_delete
47
+ unless obj.respond_to?(name + "=")
48
+ attributes.read_only
49
+ end
50
+ else
51
+ yield
52
+ end
53
+ end
54
+
55
+ def iquery(obj, index, attributes)
56
+ if obj.respond_to?(:[])
57
+ attributes.dont_delete
58
+ unless obj.respond_to?(:[]=)
59
+ attributes.read_only
60
+ end
61
+ else
62
+ yield
63
+ end
64
+ end
65
+
66
+ def names(obj)
67
+ accessible_methods(obj)
68
+ end
69
+
70
+ def indices(obj)
71
+ obj.respond_to?(:length) ? (0..obj.length).to_a : yield
72
+ end
73
+
74
+ private
75
+
76
+ def accessible_methods(obj, special_methods = false)
77
+ obj.public_methods(false).map {|m| m.to_s}.to_set.tap do |methods|
78
+ ancestors = obj.class.ancestors.dup
79
+ while ancestor = ancestors.shift
80
+ break if ancestor == ::Object
81
+ methods.merge(ancestor.public_instance_methods(false).map {|m| m.to_s})
82
+ end
83
+ methods.reject!(&special?) unless special_methods
84
+ end
85
+ end
86
+
87
+ def special?(name = nil)
88
+ @special ||= lambda {|m| m == "[]" || m == "[]=" || m =~ /=$/}
89
+ name.nil? ? @special : @special[name]
90
+ end
91
+ end
92
+ end