ext/cs__common/cs__common.c in contrast-agent-6.0.0 vs ext/cs__common/cs__common.c in contrast-agent-6.1.0
- old
+ new
@@ -57,40 +57,69 @@
VALUE contrast_patcher() {
return patcher;
}
+/* register instance alias patch */
VALUE contrast_register_patch(const char *module_name, const char *method_name,
VALUE(c_fn)(const int, VALUE *, const VALUE)) {
return _contrast_register_patch(module_name, method_name, c_fn,
IMPL_ALIAS_INSTANCE);
}
+/* register singleton alias patch */
VALUE contrast_register_singleton_patch(const char *module_name,
const char *method_name,
VALUE(c_fn)(const int, VALUE *,
const VALUE)) {
return _contrast_register_patch(module_name, method_name, c_fn,
IMPL_ALIAS_SINGLETON);
}
+/* register instance prepend patch */
VALUE contrast_register_prepend_patch(const char *module_name,
const char *method_name,
VALUE(c_fn)(const int, VALUE *,
const VALUE)) {
return _contrast_register_patch(module_name, method_name, c_fn,
IMPL_PREPEND_INSTANCE);
}
+/* register singleton prepend patch */
VALUE contrast_register_singleton_prepend_patch(const char *module_name,
const char *method_name,
VALUE(c_fn)(const int, VALUE *,
const VALUE)) {
return _contrast_register_patch(module_name, method_name, c_fn,
IMPL_PREPEND_SINGLETON);
}
+/* check if method is prepended and register instance alias or prepend patch */
+/* module name c_char "Module"; */
+/* method name c_char "method"; */
+/* c_func => pointer */
+VALUE contrast_check_and_register_instance_patch(
+ const char *module_name, const char *method_name,
+ VALUE(c_fn)(const int, VALUE *, const VALUE)) {
+
+ VALUE object, method, is_prepended, patch_type;
+ /* check if method is prepended */
+ object = rb_const_get(rb_cObject, rb_intern(module_name));
+ method = ID2SYM(rb_intern(method_name));
+ is_prepended = contrast_check_prepended(object, method, Qtrue);
+
+ if (is_prepended == Qtrue) {
+ /* prepend patch */
+ return _contrast_register_patch(module_name, method_name, c_fn,
+ IMPL_PREPEND_INSTANCE);
+ } else {
+ /* alias patch */
+ return _contrast_register_patch(module_name, method_name, c_fn,
+ IMPL_ALIAS_INSTANCE);
+ }
+}
+
static VALUE
_contrast_register_patch(const char *module_name, const char *method_name,
VALUE(c_fn)(const int, VALUE *, const VALUE),
patch_impl patch) {
VALUE contrast_bind_module = rb_funcall(rb_cModule, rb_intern("new"), 0);
@@ -131,10 +160,11 @@
case IMPL_ALIAS_SINGLETON:
impl = ID2SYM(rb_sym_alias_singleton);
break;
case IMPL_PREPEND_INSTANCE:
impl = ID2SYM(rb_sym_prepend_instance);
+ break;
case IMPL_PREPEND_SINGLETON:
impl = ID2SYM(rb_sym_prepend_singleton);
break;
}
@@ -149,10 +179,75 @@
FIX2INT(rb_funcall(rb_const_get(rb_cObject, rb_intern("RUBY_VERSION")),
rb_intern("to_i"), 0));
return ruby_version < 3;
}
+/* used for direct check on object: String.cs__prepended? *args */
+extern VALUE contrast_check_prepended(VALUE self, VALUE method_name,
+ VALUE is_instance) {
+ return _contrast_check_prepended(self, method_name, is_instance);
+}
+
+/* used for passing object to look if not called on itself.
+Contrast::Agent::Assess.cs__object_method_prepended? object, :method_name,
+true/false */
+extern VALUE contrast_lookout_prepended(VALUE self, VALUE object_name,
+ VALUE method_name, VALUE is_instance) {
+ /* object_name must be the object, the self value is needed to prevent
+ lookout for self, since is always passed first we skip it */
+ VALUE result =
+ _contrast_check_prepended(object_name, method_name, is_instance);
+ return result;
+}
+
+static VALUE _contrast_check_prepended(VALUE object, VALUE method_name,
+ VALUE is_instance) {
+ VALUE entry, ancestors, object_idx, entry_methods;
+ VALUE result = Qfalse;
+ int i;
+ int y;
+
+ /* get self ancestors */
+ ancestors = rb_mod_ancestors(object);
+ /* get the size of the array */
+ int length = RARRAY_LEN(ancestors);
+ /* Locate self in ancestors: */
+ for (i = 0; i < length; ++i) {
+ entry = rb_ary_entry(ancestors, i);
+ if (entry == object) {
+ object_idx = i;
+ break;
+ }
+ }
+
+ /* find all the prepended modules */
+ /* we have the object place in ancestors: */
+ /* [suspect, suspect, object, ...] */
+ for (i = 0; i < object_idx; ++i) {
+ entry = rb_ary_entry(ancestors, i);
+ if (is_instance == Qtrue) {
+ entry_methods = rb_class_instance_methods(1, entry, entry);
+ } else {
+ entry_methods = rb_obj_singleton_methods(1, entry, entry);
+ }
+
+ /* Loop through the instance/singleton methods of the prepended modules
+ */
+ int entry_methods_length = RARRAY_LEN(entry_methods);
+ for (y = 0; y <= entry_methods_length; ++y) {
+ if (rb_ary_entry(entry_methods, y) == method_name) {
+ result = Qtrue;
+ break;
+ }
+ }
+ if (result == Qtrue) {
+ break;
+ }
+ }
+ return result;
+}
+
void Init_cs__common(void) {
cs__send_method = rb_intern("send");
cs__alias_method_sym = ID2SYM(rb_intern("alias_method"));
/* Define symbols */
@@ -189,6 +284,12 @@
assess_policy = rb_define_module_under(assess, "Policy");
assess_propagator = rb_define_module_under(assess_policy, "Propagator");
core_extensions = rb_define_module_under(contrast, "Extension");
core_assess = rb_define_module_under(core_extensions, "Assess");
+ /* defined for direct object check */
+ rb_define_singleton_method(rb_cObject, "cs__prepended?",
+ contrast_check_prepended, 2);
+ /* defined for object lookout */
+ rb_define_singleton_method(assess, "cs__object_method_prepended?",
+ contrast_lookout_prepended, 4);
}