-1

When trying to use an instance method of a Ruby-C-Class:

RubyCClass.new.someMethod()

Ruby is raising the following error:

Error: wrong argument type RubyCClass (expected Data)

Is there any way I can instantiate the class properly such that RubyCClass is instantiated to the extent that someMethod will begin execution? In other words, is there a way I can inject Data into RubyCClass such that someMethod begins execution?

Sancarn
  • 2,575
  • 20
  • 45
  • 2
    Can you simplify this question? There is so much information here I'm not sure what the question is. – Kyle Heironimus Jan 27 '18 at 18:16
  • I tried to simplify the question, let me know if it's any better! – Sancarn Jan 27 '18 at 18:43
  • In what context are you running this code? The amount of information provided is not sufficient to answer. – Keith Bennett Jan 27 '18 at 19:06
  • Not sure what you mean by "in what context" but it's a Ruby engine inside another application which has had certain classes exposed to it via a Ruby C Extension. These classes are normally instantiated internally through other methods of the API. However in this instance, I'd rather instantiate the objects myself if possible as I want 1-size-fits-all code instead of unique codes which instantiate each class individually through their intended means. – Sancarn Jan 27 '18 at 19:23
  • That's going to be tough. You are struggling against the very design of that Ruby engine, which apparently was designed to be used _only_ to enable you to create `Data` instances. Is there no way to communicate with the developer who wrote it? – Keith Bennett Jan 28 '18 at 03:47
  • Also, what is `RubyCClass`? I assume it's a custom class provided by the author of your Ruby engine, right? – Keith Bennett Jan 28 '18 at 03:52
  • `RubyCClass` is a custom class provided by the C extension, not by the author of the ruby engine itself, or at least, they used an existing ruby engine but just added stuff to it with the C extension (as I understand it). Theres an example of a [C extension here](https://tenderlovemaking.com/2010/12/11/writing-ruby-c-extensions-part-2.html) I did talk to the developers first and they didn't know whether it was possible to inject data into an already known class. They said they'd correct their documentation, but it's taking a long time for them to do so :P – Sancarn Jan 28 '18 at 11:33

2 Answers2

0

[Note: This answer was posted when the question was drastically different; it has been edited since then.]

I'm not completely sure if your question, but I think your main problem as that you are using method instead of public_send. (And, by the way, you can get a list of an object's public methods by calling object.public_methods, in case that's helpful.)

Here is some code that illustrates what might work for you:

#!/usr/bin/env ruby

class MethodAccessibility

  attr_reader :accessibles, :inaccessibles

  def initialize
    @accessibles = []
    @inaccessibles = []
    populate_data
  end


  def method_accessible?(object, method_name, *args)
    begin
      object.public_send(method_name, args)
      true
    rescue Exception => e
      e.to_s != "Error: This method cannot be used within the User Interface"
    end
  end

  def add_to_appropriate_array(object, method_name, *args)
    accessible = method_accessible?(object, method_name, args)
    (accessible ? accessibles : inaccessibles) << method_name
  end


  def populate_data
    object = # create the object on which to call the methods
    add_to_appropriate_array(object, :method1, [:arg1, :arg2]) # for examples
    add_to_appropriate_array(object, :method2, [])
    # ...
  end
end

ma = MethodAccessibility.new
ma.accessibles # do something with this array, or the `inaccessibles` array
Keith Bennett
  • 4,722
  • 1
  • 25
  • 35
  • In this instance, I can't instantiate the object in the first place, so `public_send` doesn't help sadly. I.E. `RubyCClass.public_send(:method)` returns - `Error: undefined method 'length'` (because length is an instance method), and `RubyCClass.new.public_send(:method)` returns - `Error: wrong argument type RubyCClass (expected Data)` – Sancarn Jan 27 '18 at 19:26
0

I'm not sure where that error is being generated; is it when the engine is evaluating the value returned by your Ruby code?

If so, you could do whatever you want to do, and then return a dummy Data object:

RubyCClass.new.someMethod()
# do other things, then:
Data.new 
# or whatever it is you do to create a Data instance;
# as the final value in your code it will be returned
Keith Bennett
  • 4,722
  • 1
  • 25
  • 35
  • From [this](https://tenderlovemaking.com/2010/12/11/writing-ruby-c-extensions-part-2.html) tutorial, in the `allocate` function: `return Data_Wrap_Struct(klass, NULL, deallocate, string);` This tells us that `Data` is a void pointer of the data wrapped by the Ruby `Class`. So the class, from a C extension, is just a wrapped pointer of type `Data`? – Sancarn Jan 28 '18 at 11:37
  • Hmm... I guess this just isn't going to work unless I can get the pointer of `Data` and read the data structure behind it... Only then could I potentially recreate it. So I guess I'd need to use `Fiddle::Pointer[RubyCClass]` or something to get the pointer to where the class is stored, from here navigate to the pointer to the data struct and inject data here... xD Doesn't seem too simple to be honest, might be more worthwhile if I give up on the project myself :P – Sancarn Jan 28 '18 at 11:42