开发者

Ruby equivalent to a javascript self executing function

开发者 https://www.devze.com 2023-01-26 23:17 出处:网络
I do this a lot in javascript some_var || some_var = function(){ return \"blah\"}(); I\'m wondering what the equivalent in ruby might be so I can do

I do this a lot in javascript

some_var || some_var = function(){ return "blah"}();

I'm wondering what the equivalent in ruby might be so I can do

some_var ||= # sequence of operations

edit

the Proc.开发者_C百科new.call has been brought to my attention, but I also just came across this in someone's code:

a ||= begin
  # do some stuff
  # return some stuff
end

Is this functionally equivalent to using a Proc.new.call ??

edit2 People seem to be confused as to what I'm trying to achieve. Imagine this in javascript:

function someExpensiveFunction(){
  # do some really expensive stuff
  return "some expensive calculations"
}

a || a = someExpensiveFunction();

Obviously sets a once... calls expensive function once... In this case I don't care about scoping, I just need my return value to be a calculated sequence of events rather than a single value.

I'm pretty sure my example above a ||= begin; ... end; is equivalent...


Per your comment:

don't care about scoping... just want a clean syntax for setting a variable using ||= that involves multiple lines of code

I'm not sure I understand why you feel you have t use ||= and a lambda. You could, for example, use

if(some_var.nil?)
   # do some stuff
   some_var = result_of_doing_some_stuf
end

Or, as you put it in your example:

a ||= begin
  # do some stuff
  # return some stuff
end

It isn't clear to me why you must be using a proc or lambda.

But if you are bent on using ||= and lambdas, you could do:

calculate = lambda { 1 + 1 }
some_var ||= calculate.call


s = Proc.new { 5 + 5 }.call


I wasn't sure what part you are asking about at first. The logical || does effect your expected operations. In Ruby, the equivalent is:

somevar = "blah" unless somevar;

If somevar is nil value or a false value change to "blah". If somevar is not nil or true, the line is not executed. The opposite action would be:

somevar = "blah" if somevar;

That would assign "blah" if somevar is true or not nil.

Ruby has language features similar to the self executing function, and many javascript libraries have been inspired by those features.

Check out this page for more information:

http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_containers.html

The section on "Blocks and Iterators" would be of interest here. Also "Blocks for Transactions" and "Blocks can be closures".

Essentially the Ruby block and the ruby lambda are the closest things to the Javascript's self executing function.


You can do it with lambda blocks

some_var ||= lambda { "something" }.call

or

some_var ||= Proc.new { "something" }.call

In JS self executing functions are usually used to avoid polluting scopes, so you can use local variables internally but don't expose them. Unfortunately, if using blocks in Ruby prior to 1.9, this is not the case, where blocks don't have their own scope.

# Ruby 1.8.7
x = "some initial value"
some_var ||= Proc.new { x = 10; x + 2 }.call #=> 12
x #=> 10

so if that's the case, there is probably a better solution for what you're trying to do. Ruby ain't Javascript.}

EDIT: Sorry, I forgot about variable definition in scopes vs. variable assignment. Updated snippet to reflect that


You can do:

def run
  @a ||= begin
    x = 1 + 1
    puts "Calculated x"
    x
  end
end
puts "run = #{run}" # => Calculated x, run = 2
puts "run = #{run}" # => run = 2

Or use a lambda if you want to pass a variable

def run
  @a ||= lambda do |i|
    x = i + i
    puts "Calculated x"
    x
  end.call(1)
end
puts "run = #{run}" # => Calculated x, run = 2
puts "run = #{run}" # => run = 2

But it's less magical and more readable to use a method if you're gonna call the lambda immediately

def calc(i)
  x = i + i
  puts "Calculated x"
  x
end

def run
  @a ||= calc(1)
end
puts "run = #{run}" # => Calculated x, run = 2
puts "run = #{run}" # => run = 2


The difference between a block (begin ... end) a proc and a lambda are the way the handle return. return is not allowed in the block. Return in a Proc return from the where it's been defined and return in Lambda do what is expected

So

def f()
  a = Proc.new do
          return 5 # exit from f
      end.call
  # never called
  a+10
end 

returns 5 (and not 15)

def g()
  a = lambda do
        return 5
  end.call
  a+10
end

returns 15 (as expected)

and

def f()
  a = begin
        return 5
  end 
  a+10
end

doesn't compile.

If you are not using return in your block, then you can use begin... do (I like it by the way).

0

精彩评论

暂无评论...
验证码 换一张
取 消