How do you raise a .Net event from an IronRuby class? - ironruby

I'm trying to figure out how to implement an event in a ruby class. Specifically, I am trying to make my class implement an interface (INotifyPropertyChanged) that includes an event (PropertyChanged). I can create my add_PropertyChanged and remove_PropertyChanged methods... but then what?
This is what my class looks like so far:
class TestClass
include System::ComponentModel::INotifyPropertyChanged
def add_PropertyChanged(handler)
end
def remove_PropertyChanged(handler)
end
end

OK, I figured it out. Here is how you do it:
class TestClass
include System::ComponentModel::INotifyPropertyChanged
def initialize
#change_handlers = []
end
def add_PropertyChanged(handler)
#change_handlers << handler
end
def remove_PropertyChanged(handler)
#change_handlers.delete(handler)
end
def NotifyPropertyChanged(name)
#change_handlers.each { |h| h.invoke(self, System::ComponentModel::PropertyChangedEventArgs.new(name)) }
end
end

Related

why instantiate a class method in ruby?

What is the idea behind creating a new instance of a method inside the class << self construct?
I understand methods are put under the class << self block to make them class methods but what does it mean to create a new instance of the method itself?
class foo
class << self
def bar(param)
new.bar(some_param)
end
end
end
I think what your trying to describe is a convenience method:
class FooService
def initialize
#bar= Bar.new
end
# this does the actual work
def call
results = #bar.do_some_work
results.each do
# ...
end
end
# this is just a convenient wrapper
def self.call
new.call
end
end
This lets you call the FooService.call class method for instead of manually instantiating the class with FooService.new.call. It does not really look like that much from this simple example but its really useful for abstracting away object initialization in things like service objects or to combine initializer arguments with method arguments.
class ApiClient
def initialize(api_key)
#api_key = api_key
end
def get(path)
# ...
end
def self.get(path, api_key: ENV['API_KEY'])
new(api_key).call(path)
end
end
ApiClient.get('foo')

How can I test delegating methods using SimpleDelegator and RSpec?

I'm using Ruby 1.9.3 and trying to make some tests with RSpec.
I have a class:
class A
def method1
"test"
end
end
class B < SimpleDelegator
def initialize(events)
#events = events
end
end
Now I'm trying to test delegation behaviour:
require 'spec_helper'
RSpec.describe B do
let(:a) { A.new }
let(:b) { B.new(a) }
it "Should delegate unknown calls to A object" do
expect(b.method1).not_to eq(nil)
end
end
I get the following error:
NoMethodError:
undefined method `method1' for nil:B
Seems that the test would pass if add method_missing manually:
class B < SimpleDelegator
def initialize(events)
#events = events
end
def method_missing(meth, *args, &blk)
#events.send(meth, *args, &blk)
end
end
What I'm doing wrong here?
Thanks
The problem is that you added a initializer to the class B without calling super and passing the instance you want to decorate. Your code should look like this:
class A
def method1
"test"
end
end
class B < SimpleDelegator
def initialize(events)
#events = events
super(events)
end
end
You don't need to define an initialize method on B. SimpleDelegator defines one for you. When you defined your own initialize method, you overrode the initialize method you inherited from the SimpleDelegator class.
Try this:
class A
def method1
"test"
end
end
class B < SimpleDelegator
end
This is from irb: B.new(A.new).method1 #=> "test"
You could define your own initialize method and call super, but I wouldn't unless you really had to.

Add method to standard class inside a module

I want to add new method to class String, for example. But I don't want to make this change global (keeping classes clean is good, yes?).
So, instead of this code
class String
def is_palindrome?
self == self.reverse
end
end
module MyModule
class MyClass
def filter_palindrome(str_arr)
str_arr.select { |s| s.is_palindrome? }
end
end
end
I want to have something like this:
module MyModule
class String
def is_palindrome?
self == self.reverse
end
end
class MyClass
def self.filter_palindrome(str_arr)
str_arr.select { |s| s.is_palindrome? }
end
end
end
But, of course, it's not working (undefined method 'is_palindrome?' for :String). So, is there any point in what I want? And if there is, what is the best way to achieve it?
If you are using Ruby 2.0, you can try refinements.
module MyModule
module StringAlter
refine String do
def is_palindrome?
self == self.reverse
end
end
end
end
using MyModule::StringAlter
module MyModule
class MyClass
def self.filter_palindrome(str_arr)
str_arr.select { |s| s.is_palindrome? }
end
end
end
If prior to Ruby 2.0, you cannot achieve this directly. Changes made to String will be global. However, instead of s.is_palindrome?, why not write a helper method and call it like is_palindrome?(s). Then you don't have to reopen String and you can restrict is_palindrome? to be available only in some given scope.
This is the way Python does (self), and so as to C# extension method.

Ruby global variable alternative

I know global variables should never be used but right now it's the only thing that I can get to work. So I'm looking for alternatives. What I want to do is pass #array which is is in method two in class New, to method one. The only way I was able to accomplish this is with $array.
module Test::Abc
class << self
def one
....
end
class New
def two
#array=[]
end
end
end
end
Here's what I did to get the result I needed...
module Test::Abc
class << self
def one(array)
....
end
end
class New
def two
#array=[]
array=#array
Test::Abc::one(array)
end
end
end
Here's what I came up with as a solution...
module Test::Abc
class << self
def one(array)
....
end
end
class New
def two
#array=[]
array=#array
Test::Abc::one(array)
end
end
end
Along with your answer, this should also work (slight modification):
module Test::Abc
class << self
def one(array)
....
end
end
class New
def two
#array=[]
Test::Abc::one(#array)
end
end
end

Returning dynamically generated module from a method

I have a bunch of classes with similiar logic like this
class ApiWrapper
class << self
attr_accessor :app_id, :app_key
def configure
yield self
end
end
end
I want to extract this logic to a module similar to Ruby Struct class to be able to do something like this
class ApiWrapper
include Configurable.instance :app_id, :app_key
end
How can I do this?
From documentation
fred = Module.new do
def meth1
"hello"
end
def meth2
"bye"
end
end

Resources