therubyracer-freebsd 0.10.1

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.
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