Ruby Bet you cant do this in Java
Ruby! (Bet you can’t do this in Java!) 21 -Nov-20
Ruby is dynamic n n n n n In Ruby, anything can be changed, anytime Variables don’t have a type; the type belongs to the value currently in the variable Methods can be defined—and undefined Methods can be added to a class—at run time Methods can be added to individual objects Strings can be compiled and executed I’m sure there’s more, but you get the idea Why was Ruby written? The author, Yukihiro "Matz" Matsumoto, wanted a language that was fun to program in!
Defining and undefining methods n n n To define a method: def name (parameters) body // the last value is the returned value end To remove a method; undef name To add an instance method to an existing class, first “open” the class n class String def nchars length end
Class and object methods n To add a class method while inside the Person class: def self. species ‘human’ end n To add a class method from elsewhere: def Person. species ‘human’ end n To add a method to an individual object: def oscar. mood ‘grouchy’ end
Numbers n Numbers may be written in decimal, hexadecimal, octal, or binary n n n Numbers larger than four bytes are automatically treated as Bignum objects For readability, numbers may contain (but not begin or end with) underscores n n Decimal: 3405691582 Hex: 0 x. CAFEBABE or 0 XCAFEBABE Octal: 031277535276 or 0 o 31277535276 Binary: 0 b 11001010111111101010111110 or 0 Betc. Examples: 3_405_691_582, 0 b_111_101 Integers may be indexed to retrieve their bits n Example: 5. step(0, -1) { |i| print 6[i] } 000110
Attributes (instance variables) n n n Attributes (instance variables) of an object are written with an @ prefix: @name, @age, @hobbies, @favorite_language By default, attributes are private You can write getters: n n def name @name end You can write setters: n n n def name=(new_name) @name = new_name end When you define the setter, there is no space before the = in the header When you call the setter, you can use a space: teacher. name = "Saj“ n Yes, we are calling the method name= !
Shorthand for getters and setters n Writing code for routine getters and setters is tedious, so in Ruby we don’t have to do it n Shorthand for creating getters: attr_reader : name, : age, : hobbies n n n Note the use of symbols, not variables or strings Shorthand for creating setters: attr_writer : name, : hobbies Shorthand for creating both at once: attr_accessor : name, : favorite_language By the way, these aren’t special Ruby syntax; they are methods that write the getters and setters for you Ruby uses lots of metaprogramming: programs that write programs
Access controls n n n Public methods can be called from anywhere Protected methods can be called only within the class and its subclasses Private methods cannot be called with an explicit receiver, only with an implicit self In Ruby, methods are public by default The functions public, protected, and private can be called with or without arguments n With arguments, they set the access of the named methods n n Example: private : dump, : swear With no arguments, they set the default access for all subsequent methods
eval n eval executes a string n n Here’s how you don’t want to use this: n n n Example: eval "puts x + 2" eval gets This can be a serious security risk Here’s what Ruby does about this: n n All data that comes from the outside world, and all data derived from that data, can automatically be marked as tainted Ruby has five $SAFE levels, each of which has a long list of things you cannot do with a tainted object
Arrays n An array literal can be written with brackets and commas n n n a = [1, 1, 2, 3, 5, 8, 13, "hi"] Arrays are zero based: a[2] == 2 Arrays can be expanded n a = a + [21, 34] pa n n [1, 2, 3, 5, 8, 13, "hi", 21, 34] Arrays can be treated as stacks, with a. push(v) and v = a. pop The join(string) method creates a string of the elements of the array, with the given string between each pair of elements You can take slices of arrays, sort them, find unique elements, perform set operations, transpose 2 -dimensional arrays, etc. n Before you write methods to manipulate arrays, you should look to see whether the method you want has already been written
Some Array methods n n n n n min, max – return the smallest or largest element uniq – return an array with no duplicate elements compact – return an array with no nil elements sort – return a sorted array & – perform an intersection (only elements in both) | – perform a union (elements in either) grep(regexp) – return elements matching the pattern push(element) – add the element to the end of the array pop – remove and return the last element shift – remove and return the first element
Chaining n Nondestructive methods can usually be chained n n Example: x = gets. chomp. strip. downcase Many destructive methods return nil if they make no changes in the receiver, hence cannot be chained n Example: x = gets. chomp!. strip!. downcase! will result in a runtime error
Regular expressions n n Ruby has regular expressions, almost identical to the way they are done in Perl Example (from the textbook): n n hamlet = "The slings and arrows of outrageous fortune. " hamlet. scan(/w+/) ["The", "slings", "and", "arrows", "of", "outrageous", "fortune"]
Hashes n A hash (hash table) literal can be written with braces, commas, and the => arrow n n h = {: apple => : red, : banana => : yellow, : cherry => : red} Element access is similar to that for arrays: n h[: banana] n n h[: apple] = : green ph n n : yellow {: banana=>: yellow, : cherry=>: red, : apple=>: green} You can use any types for keys and values, but the characteristics of symbols make them especially useful as keys
Loops in Ruby has several loops n n n while condition do statements end begin statements end while condition until condition statements end n begin statements end until condition n for variable in range do statements end n statement while condition n statement until condition However, loops are not used as often in Ruby as in other languages Instead, Ruby programmers use iterator methods
Iterators n n n An iterator returns values one at a time The syntax is object. iterator { |value| statement } or object. iterator do |value| statements end The object is typically an array, a range, or a hash, but it can be any object with a coroutine
Iterators n n n n In Ruby, loops are considered low-level, to be used only when there is no appropriate iterator collection. each – step through every element n. times – do a block n times n. downto(limit) – step from n down to and including limit n. upto(limit) – step from n up to and including limit string. each_line – get each line from a string. each_char – get each character (as an integer) from a string
Example use of an iterator n n a = [1, 1, 2, 3, 5, 8, 13] a. each { |i| print " #{i}" } n n a. each do |i| print " #{i}" end n n Output: 1 1 2 3 5 8 13 In the above, each is a method A block is a chunk of code enclosed by {. . . } or by do. . . end By convention, braces are used for single-line blocks, do. . . end for multiline blocks
Blocks n n A block is a chunk of code that can be passed as a parameter to a method Blocks are basically function literals n n A block isn’t a statement—it can’t be used alone It’s passed as an “invisible” parameter, and executed with the yield statement
Simplest use of yield n n def three_times puts "----- three_times“ yield end three_times { puts "hello" } n ----- three_times hello
My version of loop n n def my_loop yield while true end a = [1, 2, 3, 5, 8, 13, "hi"] my_loop do break if a. empty? print a. pop end puts "Done" n hi 1385321 Done
Fibonacci numbers n n def fibonacci_upto n i 1, i 2 = 1, 1 while i 1 < n yield i 1, i 2 = i 2, i 1 + i 2 end fibonacci_upto(100) { |f| print " ", f } n 1 1 2 3 5 8 13 21 34 55 89
Passing a parameter to the block n n def count_to n puts "----- count_to #{n}" for i in 1. . n yield end count_to 3 { puts "hello" } n ----- count_to 3 hello
Returning a value from a coroutine n n def count_to_3 puts "----- count_to_3“ yield 1 yield 2 yield 3 end count_to_3 { |result| puts result } n ----- count_to_3 1 2 3
Context n n n def do_it a = [1, 2, 3, 5, 8, 13, "hi"] x = 4 # local variable a. my_each { |v| print v * x, "; " } end do_it n 4; 8; 12; 20; 32; 52; hihi; Notice that the print v*x statement is being executed in the my_each method, not in the do_it method However, x is local to the do_it method How can this be? n n Answer: The block carries its context along with it A block is a closure
More iterators n n collection. each_index – iterate over the indices of a collection. each_with_index – iterate over the values in a collection, along with their indices n n n Example: lineup. each_with_index { |man, pos| print pos, man } hash. each_key – iterate over keys hash. each_value – iterate over values hash. each_pair – iterate over key-value pairs collection. select { |v| condition } – choose only items that meet the condition collection. map { |v| transformation } – create a new collection with the transformation applied to each item
Procs n A proc is a procedure that is stored in a variable n n p = Proc. new { |x, y, z| puts 100 * x + 10 * y + z } n n n Call a proc by using the variable’s call method p. call 14, 9, 2 1492 max = Proc. new do |a, b| if a > b then a else b end n n puts max. call(0. 8, 0. 12) 0. 8
Procs are closures, too n def scoper p x=3 p. call end n x = 77 p = Proc. new { puts x } x = 19 scoper p n 19 n n n
Procs as parameters n n A block passed as a parameter to a function becomes a Proc The formal parameter must be last, and is prefixed with an ampersand n n n def foo &b b. call end foo { puts "Hi!" } Hi!
Reflection n n n The class method returns the class of an object The superclass method returns the superclass of an object The name method returns the name of a class The new method creates a new object of a class The methods method returns the methods than an object knows how to respond to The instance_variables method returns the attributes of an object There are many other methods to examine (and modify!) a Ruby program while it is executing
Undefined methods n n n If an undefined method is called, Ruby raises a No. Method. Error If you supply a method_missing method for your object, Ruby will call this instead Example: n n n def method_missing(name, *args) puts "Call of missing method" + " #{name}(#{args. join ', ' })" end fribble 2, : ace Call of missing method fribble(2, ace)
Adding methods to a class n n To add (or replace) a method to a class, just open up the class definition again and define the method You can even do this with Ruby’s built-in classes class Array def every_other i=0 while i < self. length yield self[i] i += 2 end end [1, 2, 3, 5, 8, 13]. every_other {|v| print v, "; "} n 1; 3; 8;
Modules n Classes in Ruby, as in Java, may extend only one other class n n Example: class Enterprise < Starship Everything in the superclass is available in the subclass A module is defined just like a class (using the word module instead of class) Modules cannot be instantiated, but they may be included in a class n n Including a module is like copying the code into the class Example: class Enterprise < Starship include Location. . .
Metaprogramming n n Metaprogramming is using programs to write programs Example uses: n n You want to add “boilerplate” code to every method You want to “wrap” functions so that they print to a log when they are called and when they return You want to examine a database and automatically create methods to access that database You can do metaprogramming in any language, but. . . n In Ruby the program can make the changes to itself, as it runs
Rails n n n Ruby on Rails (or just Rails) is the “killer app” that catapulted Ruby to prominence Web applications are extremely complex server-side programs that communicate with the user’s browser using HTML, XML, and CSS, do session management, and handle a server-side database Rails uses metaprogramming to write your web application for you n n It’s hard to convey just how much work this saves The downside? You still have to understand the programs that it writes
The End
- Slides: 36