I really need to make use of something similar to the Single method, which:
Returns the only element of a sequence, and throws an exception if there is not exactly one element in the sequence.
Obviously I can add an extension/refinement for convenience.
But does something similar already exists?
Maybe in ActiveSupport or other library?
No, nothing in the Standard Library (nor ActiveSupport, I believe), but easy enough to implement.
module EnumeratorWithSingle
class TooManyValuesException < StandardError; end
class NotEnoughValuesException < StandardError; end
refine Enumerator do
def single
val = self.next
begin
self.next
raise TooManyValuesException
rescue StopIteration
val
end
rescue StopIteration
raise NotEnoughValuesException
end
end
end
module Test
using EnumeratorWithSingle
puts [1].each.single # 1
puts [1, 2].each.single # EnumeratorWithSingle::TooManyValuesException
end
Related
I have method
common method
def error_notification
<notification_code>
end
whenever the code catches an exception I need to call this method in the rescue block
eg: example
def error_method
begin
<some_code>
rescue => e
error_notification
end
end
Instead of calling all rescue blocks, there is any standard way to write the code
While what you have shown is in no way out of the normal realm of things but you could can certainly DRY this up a bit if you are using it frequently by creating a wrapper for the calls.
Simple Example:
def guard(&block)
begin
block.call
rescue => e
error_notification
end
end
Then use where needed as
def error_method
guard do
some_code
end
end
That being said generally you would want to rescue specific errors not every StandardError but that design decision is up to you.
Additionally if this is specific to controller methods (you didn't really specify), ActiveSupport offers a method called rescue_from that you could utilize as well and would generally be considered more idiomatic in rails application Docs
For Example your setup would look like
class ApplicationController < ActionController::Base
rescue_from StandardError, with: error_notification
private
def error_notification
notification_code
end
end
I'm trying to wrap my head around delegation vs. inheritance so I'm manually delegating a version of Array. One of the specific reasons I read to do this is because when you use things like enumerables, your returned value on the inherited methods reverts back to the parent class (i.e. Array). So I did this:
module PeepData
# A list of Peeps
class Peeps
include Enumerable
def initialize(list = [])
#list = list
end
def [](index)
#list[index]
end
def each(...)
#list.each(...)
end
def reverse
Peeps.new(#list.reverse)
end
def last
#list.last
end
def join(...)
#list.join(...)
end
def from_csv(csv_table)
#list = []
csv_table.each { |row| #list << Peep.new(row.to_h) }
end
def include(field, value)
Peeps.new(select { |row| row[field] == value })
end
def exclude(field, value)
Peeps.new(select { |row| row[field] != value })
end
def count_by_field(field)
result = {}
#list.each do |row|
result[row[field]] = result[row[field]].to_i + 1
end
result
end
protected
attr_reader :list
end
end
When I instantiate this, my include and exclude function great and return a Peeps class but when using an enumerable like select, it returns Array, which prevents me from chaining further Peeps specific methods after the select. This is exactly what I'm trying to avoid with learning about delegation.
p = Peeps.new
p.from_csv(csv_generated_array_of_hashes)
p.select(&:certified?).class
returns Array
If I override select, wrapping it in Peeps.new(), I get a "SystemStackError: stack level too deep". It seems to be recursively burying the list deeper into the list during the select enumeration.
def select(...)
Peeps.new(#list.select(...))
end
Any help and THANKS!
I would recommend using both Forwardable and Enumerable. Use Forwardable to delegate the each method to your list (to satisfy the Enumerable interface requirement), and also forward any Array methods you might want to include that are not part of the Enumerable module, such as size. I would also suggest not overriding the behavior of select as it is supposed to return an array and would at the very least lead to confusion. I would suggest something like the subset provided below to implement the behavior you are looking for.
require 'forwardable'
class Peeps
include Enumerable
extend Forwardable
def_delegators :#list, :each, :size
def initialize(list = [])
#list = list
end
def subset(&block)
selected = #list.select(&block)
Peeps.new(selected)
end
protected
attr_reader :list
end
Example usage:
peeps = Peeps.new([:a,:b,:c])
subset = peeps.subset {|s| s != :b}
puts subset.class
peeps.each do |peep|
puts peep
end
puts peeps.size
puts subset.size
produces:
Peeps
a
b
c
3
2
I think that if Peeps#select will return an Array, then it is OK to include Enumerable. But, you want Peeps#select to return a Peeps. I don't think you should include Enumerable. It's misleading to claim to be an Enumerable if you don't conform to its interface. This is just my opinion. There is no clear consensus on this in the ecosystem. See "Examples from the ecosystem" below.
If we accept that we cannot include Enumerable, here's the first implementation that comes to my mind.
require 'minitest/autorun'
class Peeps
ARRAY_METHODS = %i[flat_map map reject select]
ELEMENT_METHODS = %i[first include? last]
def initialize(list)
#list = list
end
def inspect
#list.join(', ')
end
def method_missing(mth, *args, &block)
if ARRAY_METHODS.include?(mth)
self.class.new(#list.send(mth, *args, &block))
elsif ELEMENT_METHODS.include?(mth)
#list.send(mth, *args, &block)
else
super
end
end
end
class PeepsTest < Minitest::Test
def test_first
assert_equal('alice', Peeps.new(%w[alice bob charlie]).first)
end
def test_include?
assert Peeps.new(%w[alice bob charlie]).include?('bob')
end
def test_select
peeps = Peeps.new(%w[alice bob charlie]).select { |i| i < 'c' }
assert_instance_of(Peeps, peeps)
assert_equal('alice, bob', peeps.inspect)
end
end
I don't normally use method_missing, but it seemed convenient.
Examples from the ecosystem
There doesn't seem to be a consensus on how strictly to follow interfaces.
ActionController::Parameters used to inherit Hash. Inheritance ceased in Rails 5.1.
ActiveSupport::HashWithIndifferentAccess still inherits Hash.
As mentioned in the other answer, this isn't really proper usage of Enumerable. That said, you could still include Enumerable and use some meta-programming to override the methods that you want to be peep-chainable:
module PeepData
class Peeps
include Enumerable
PEEP_CHAINABLES = [:map, :select]
PEEP_CHAINABLES.each do |method_name|
define_method(method_name) do |&block|
self.class.new(super(&block))
end
end
# solution for select without meta-programming looks like this:
# def select
# Peeps.new(super)
# end
end
end
Just so you know, this really has nothing to do with inheritance vs delegation. If Peeps extended Array, you would have the exact same issue, and the exact solution above would still work.
I would like to have something like this:
class A
def only_B_can_call_me
'called_by_B'
end
end
class B
def do_stuff(a)
a.only_B_can_call_me
end
end
class C
def do_stuff(a)
a.only_B_can_call_me # how to forbid it?
end
end
B.new.do_stuff(A.new) # => 'called_by_B'
C.new.do_stuff(A.new) # => it should not be allowed!!! but how to do it?
One way to do this is to make only_B_can_call_me a private method and use a.send(:only_B_can_call_me) inside B. OK, it works. But I could be tempted in doing the same thing inside C... so, I think it is not a good approach. Is there any other way to do this? (Allow a method be accessed just by instances of a specific class.)
(I know that ultimately it is always possible to access any method from anywhere using send. But I want to keep myself away from send in this case.)
There are no clear solutions. If B can do it, so can C. Unlike some other languages, ruby doesn't have "internal" or "package" visibility modifier, which could help you if A and B were in the same "package", but C was external. If the method is private, even B has to use send. If it's public, C can just call it. B is not a subclass of A in your example, so protected modifier doesn't apply.
One dirty-dirty way would be to check caller in only_B_can_call_me. It returns the entire callstack. So you can check if it is, indeed, B or reject otherwise. But this is super-fragile and totally not recommended.
This is the best I could do with help of #Sergio Tulentsev:
class A
def only_B_can_call_me(b)
return unless b.class == B # here you are asking
'called_by_B'
end
end
class B
def do_stuff(a)
a.only_B_can_call_me(self) # how to forbid it? ask if self is B
end
end
class C
def do_stuff(a)
a.only_B_can_call_me(self) # how to forbid it? ask if self is B
end
end
Other way is using subclass:
class A
def only_B_can_call_me
'called_by_B'
end
end
class B < A
def do_stuff
self.only_B_can_call_me
end
end
class C
def do_stuff
self.only_B_can_call_me # how to forbid it?, like this C hasn't the method, B does
end
end
puts(B.new.do_stuff) # => 'called_by_B'
puts(C.new.do_stuff) # => it should not be allowed!!! but how to do it?
Sergio's answer is correct, however if you really need a hack take a look at the code below:
class CallerClass
def self.get (c)
line = c.first.scan(/^.*:(.*):.*/).first.first.to_i
file = c.first.scan(/^(.*?):/).first.first
func = c.first.scan(/:in `(.*)?'/).first.first
fc = File.readlines(file)
caller_class = nil
caller_class = '<main>' if func == '<main>'
line.downto(0) do |it|
break if caller_class
caller_class = fc[it].scan(/^\s*class\s+(.*)\s+/).first.first if fc[it] =~ /^\s*class\s+(.*)\s+/
end
caller_class
end
end
class A
def only_B_can_call_me
caller_class = CallerClass.get(caller)
raise "'#{caller_class}' is not an allowed caller" unless caller_class == 'B'
'called_by_B'
end
end
class B
def do_stuff
A.new.only_B_can_call_me
end
end
class C
def do_stuff
A.new.only_B_can_call_me
end
end
B.new.do_stuff #called_by_B
C.new.do_stuff #Raises exception
OBS. This is a fragile parsing of ruby code using regex, It's a HACK you've been warned!!
I want to make a ruby gem which standardizes a serious of APIs.
The logic associated with connecting to each API needs to be abstracted into .rb files. To load each of the API's logic, I'm looping through the files of a folder:
# Require individual API logic
Dir[File.dirname(__FILE__) + "/standard/apis/*.rb"].each do |file|
require file
end
Each API is a constant of the StandardAPI, so I can to iterate some code over each API:
StandardAPI.constants.each do |constant|
# Standardize this stuff
end
However, I have a VERSION constant too. It loops over my API logic classes just fine, but when I gets to VERSION, I run into:
:VERSION is not a class/module (TypeError)
How can I loop over each of the APIs ignoring constants that aren't my required classes?
Since Module#constants returns an array of symbols, you have to first look up the constant with Module#const_get:
Math.const_get(:PI) #=> 3.141592653589793
StandardAPI.const_get(:VERSION) #=> the value for StandardAPI::VERSION
Then you can check if it is a class:
Math.const_get(:PI).class #=> Float
Math.const_get(:PI).is_a? Class #=> false
StandardAPI.const_get(:VERSION).is_a? Class #=> false
To filter all classes:
StandardAPI.constants.select { |sym| StandardAPI.const_get(sym).is_a? Class }
Another approach is to collect the sub classes, maybe with Class#inherited:
# standard_api/base.rb
module StandardAPI
class Base
#apis = []
def self.inherited(subclass)
#apis << subclass
end
def self.apis
#apis
end
end
end
# standard_api/foo.rb
module StandardAPI
class Foo < Base
end
end
# standard_api/bar.rb
module StandardAPI
class Bar < Base
end
end
StandardAPI::Base.apis
#=> [StandardAPI::Foo, StandardAPI::Bar]
It seems you should be able to use is_a?
class Test
end
Test.is_a?(Class)
=> true
VERSION = 42
VERSION.is_a?(Class)
=> false
I guess you can catch that exception and proceed
StandardAPI.constants.each do |constant|
begin
# Standardize this stuff
rescue TypeError
next
end
end
or as #jonas mentioned
StandardAPI.constants.each do |constant|
if constant.is_a?(Class)
# Standardize this stuff
end
end
This question is not about how to use Enumerators in Ruby 1.9.1 but rather I am curious how they work. Here is some code:
class Bunk
def initialize
#h = [*1..100]
end
def each
if !block_given?
enum_for(:each)
else
0.upto(#h.length) { |i|
yield #h[i]
}
end
end
end
In the above code I can use e = Bunk.new.each, and then e.next, e.next to get each successive element, but how exactly is it suspending execution and then resuming at the right spot?
I am aware that if the yield in the 0.upto is replaced with Fiber.yield then it's easy to understand, but that is not the case here. It is a plain old yield, so how does it work?
I looked at enumerator.c but it's neigh on incomprehensible for me. Maybe someone could provide an implementation in Ruby, using fibers, not 1.8.6 style continuation-based enumerators, that makes it all clear?
Here's a plain ruby enumerator that uses Fibers and should pretty much behave like the original:
class MyEnumerator
include Enumerable
def initialize(obj, iterator_method)
#f = Fiber.new do
obj.send(iterator_method) do |*args|
Fiber.yield(*args)
end
raise StopIteration
end
end
def next
#f.resume
end
def each
loop do
yield self.next
end
rescue StopIteration
self
end
end
And in case anyone is feeling uneasy about using exceptions for control flow: The real Enumerator raises StopIteration at the end, too, so I just emulated the original behaviour.
Usage:
>> enum = MyEnumerator.new([1,2,3,4], :each_with_index)
=> #<MyEnumerator:0x9d184f0 #f=#<Fiber:0x9d184dc>
>> enum.next
=> [1, 0]
>> enum.next
=> [2, 1]
>> enum.to_a
=> [[3, 2], [4, 3]]
Actually in your e = Bunk.new.each the else clause is not executed initially. Instead the 'if !block_given' clause executes and returns an enumerator object. The enumerator object does keep a fiber object internally. (At least that is what it looks like in enumerator.c)
When you call e.each it is calling a method on an enumerator which uses a fiber internally to keep track of its execution context. This method calls the Bunk.each method using the fibers execution context. The Bunk.each call here does execut the else clause and yields up the value.
I do not know how yield is implemented or how a fiber tracks the execution context. I haven't looked at that code. Almost all of the enumerator and fiber magic is implemented in C.
Are you really asking how fibers and yield are implemented? What level of detail are you looking for?
If I am off base please correct me.
As the other posters noted, I believe it creates its own private "fiber" [in 1.9]. In 1.8.7 (or 1.8.6 if you use the backports gem) somehow or other it does the same thing (perhaps because all threads in 1.8 are the equivalent of fibers, it just uses them?)
Thus in 1.9 and 1.8.x, if you chain several of them together
a.each_line.map.each_with_index { }
It actually flows through that whole chain with each line, kind of like a pipe on the command line
http://pragdave.blogs.pragprog.com/pragdave/2007/12/pipelines-using.html
HTH.
I think this would be more accurate. Calling each on the enumerator should be the same as calling the original iterator method. So I would slightly change the original solution to this:
class MyEnumerator
include Enumerable
def initialize(obj, iterator_method)
#f = Fiber.new do
#result = obj.send(iterator_method) do |*args|
Fiber.yield(*args)
end
raise StopIteration
end
end
def next(result)
#f.resume result
end
def each
result = nil
loop do
result = yield(self.next(result))
end
#result
end
end