Difference between revisions of "Ruby"
Postmodern (Talk | contribs) (put stdin/stdout first) |
(→Ensure) |
||
(73 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
'''Ruby''' is an [[interpreted languages|interpreted language]], dynamically, reflective, semi-Functional and Object Orientated scripting language written in [[C]]. Ruby is said to be semi-Functional because it supports higher-order functions (aka lambdas) and closures (aka blocks). Ruby was created by [http://en.wikipedia.org/wiki/Yukihiro_Matsumoto Yukihiro "Matz" Matsumoto] and was first released in 1995. | '''Ruby''' is an [[interpreted languages|interpreted language]], dynamically, reflective, semi-Functional and Object Orientated scripting language written in [[C]]. Ruby is said to be semi-Functional because it supports higher-order functions (aka lambdas) and closures (aka blocks). Ruby was created by [http://en.wikipedia.org/wiki/Yukihiro_Matsumoto Yukihiro "Matz" Matsumoto] and was first released in 1995. | ||
− | Matz's goal was to combine powerful features from various other [[programming]] languages, | + | Matz's goal was to combine powerful features from various other [[programming]] languages, to create a [[programming language]] maximized for developer happiness; as opposed to computational efficiency. Ruby's Object Model mirrors that of Smalltalk, the syntax shares some similarities with [[Bash]], [[Perl]], [[Python]], and the scoping rules for closures were taken from [[LISP]]. |
+ | <font size="-2">Special thanks to [[User:Postmodern|Postmodern]] and [[User:Ohdazed|Ohdazed]] for their contributions to this article.</font> | ||
= Basics = | = Basics = | ||
Line 13: | Line 14: | ||
IRB, or the Interactive Ruby Console, comes bundled with Ruby and allows you to interactively run code right from your command line. IRB can be invoked from your terminal simply by typing 'irb'. | IRB, or the Interactive Ruby Console, comes bundled with Ruby and allows you to interactively run code right from your command line. IRB can be invoked from your terminal simply by typing 'irb'. | ||
− | |||
» irb --help | » irb --help | ||
Usage: irb.rb [options] [programfile] [arguments] | Usage: irb.rb [options] [programfile] [arguments] | ||
Line 40: | Line 40: | ||
-v, --version Print the version of irb | -v, --version Print the version of irb | ||
− | + | <pre> | |
− | irb(main):001:0> puts 'woot' | + | $ irb |
+ | irb(main):001:0>puts 'woot' | ||
woot | woot | ||
=> nil | => nil | ||
− | irb(main):002:0> | + | irb(main):002:0> |
</pre> | </pre> | ||
Running irb --simple-prompt will provide you with a more basic looking Ruby shell. | Running irb --simple-prompt will provide you with a more basic looking Ruby shell. | ||
+ | |||
<pre> | <pre> | ||
− | + | $ irb --simple-prompt | |
>> puts 'woot' | >> puts 'woot' | ||
woot | woot | ||
=> nil | => nil | ||
− | |||
− | |||
</pre> | </pre> | ||
You can use either 'exit', 'quit', or 'irb_exit' to close IRB and return to your terminal. | You can use either 'exit', 'quit', or 'irb_exit' to close IRB and return to your terminal. | ||
<pre> | <pre> | ||
− | + | $ irb --simple-prompt | |
− | + | ||
>> exit | >> exit | ||
− | + | $ # back in our terminal :D | |
</pre> | </pre> | ||
Line 99: | Line 98: | ||
− | == Variables | + | == Variables == |
===Local=== | ===Local=== | ||
Line 120: | Line 119: | ||
Instance variables begin with the '@' symbol. Accessing an uninitialzed instance will return the <kbd>nil</kbd> value. | Instance variables begin with the '@' symbol. Accessing an uninitialzed instance will return the <kbd>nil</kbd> value. | ||
− | < | + | {{code|text=<source lang="ruby"> |
>> @instance | >> @instance | ||
=> nil | => nil | ||
>> @instance = 'ohdae' | >> @instance = 'ohdae' | ||
=> "ohdae" | => "ohdae" | ||
− | </ | + | </source>}} |
Instance variables can also be defined at the Class/Module level: | Instance variables can also be defined at the Class/Module level: | ||
− | < | + | {{code|text=<source lang="ruby"> |
>> module Settings | >> module Settings | ||
>> @config = {:verbose => false} | >> @config = {:verbose => false} | ||
Line 137: | Line 136: | ||
>> Settings.config | >> Settings.config | ||
=> {:verbose => false} | => {:verbose => false} | ||
− | </ | + | </source>}} |
===Class Variables=== | ===Class Variables=== | ||
+ | |||
Class variables are shared by all methods within a Class or Module. These are created by using two '@' symbols at the beginning of your variable. | Class variables are shared by all methods within a Class or Module. These are created by using two '@' symbols at the beginning of your variable. | ||
Trying to initialize a class variable outside of a class will throw an error. | Trying to initialize a class variable outside of a class will throw an error. | ||
− | < | + | {{code|text=<source lang="ruby"> |
>> @@classvar | >> @@classvar | ||
NameError: uninitialized class variable @@classvar in Object | NameError: uninitialized class variable @@classvar in Object | ||
Line 154: | Line 154: | ||
>> Blackhat.classvar | >> Blackhat.classvar | ||
=> "ohhai" | => "ohhai" | ||
− | </ | + | </source>}} |
===Predefined Variables=== | ===Predefined Variables=== | ||
Line 160: | Line 160: | ||
Certain variables are pre-defined into Ruby. The values of these variables cannot be changed. | Certain variables are pre-defined into Ruby. The values of these variables cannot be changed. | ||
− | * <kbd>self</kbd>: Represents the current scope. Similar to <kbd>this</kbd> from Java. | + | * <kbd>self</kbd>: Represents the current scope. Similar to <kbd>this</kbd> from [[Java]]. |
* <kbd>nil</kbd>: The null object. | * <kbd>nil</kbd>: The null object. | ||
* <kbd>true</kbd>: Boolean true. | * <kbd>true</kbd>: Boolean true. | ||
* <kbd>false</kbd>: Boolean false. | * <kbd>false</kbd>: Boolean false. | ||
+ | |||
+ | == Data Types == | ||
===Boolean Values=== | ===Boolean Values=== | ||
Ruby defines two boolean values, <kbd>true</kbd> and <kbd>false</kbd>: | Ruby defines two boolean values, <kbd>true</kbd> and <kbd>false</kbd>: | ||
− | + | {{code|text=<source lang="ruby"> | |
− | < | + | |
>> 1 == 1 | >> 1 == 1 | ||
=> true | => true | ||
>> 1 == 2 | >> 1 == 2 | ||
=> false | => false | ||
− | </ | + | </source>}} |
===Integers=== | ===Integers=== | ||
Line 180: | Line 181: | ||
Ruby also provides Integer literals: | Ruby also provides Integer literals: | ||
− | < | + | {{code|text=<source lang="ruby"> |
>> 10 | >> 10 | ||
=> 10 | => 10 | ||
>> 010 # octal | >> 010 # octal | ||
− | => | + | => 8 |
>> 0x0a # hexadecimal | >> 0x0a # hexadecimal | ||
=> 10 | => 10 | ||
>> 1_000_000 # short-hand for big values | >> 1_000_000 # short-hand for big values | ||
=> 1000000 | => 1000000 | ||
− | </ | + | </source>}} |
In Ruby, Integers are also Objects, which you can call methods on: | In Ruby, Integers are also Objects, which you can call methods on: | ||
− | < | + | {{code|text=<source lang="ruby"> |
>> 0x42.chr | >> 0x42.chr | ||
=> "A" | => "A" | ||
− | </ | + | </source>}} |
===Floats=== | ===Floats=== | ||
Line 202: | Line 203: | ||
Ruby also provides floating point decimal literals: | Ruby also provides floating point decimal literals: | ||
− | < | + | {{code|text=<source lang="ruby"> |
>> 1.5 | >> 1.5 | ||
=> 1.5 | => 1.5 | ||
>> 1.5e10 | >> 1.5e10 | ||
=> 15000000000.0 | => 15000000000.0 | ||
− | </ | + | </source>}} |
Floats are also Objects: | Floats are also Objects: | ||
− | < | + | {{code|text=<source lang="ruby"> |
>> 1.5.round | >> 1.5.round | ||
=> 2 | => 2 | ||
− | </ | + | </source>}} |
=== Strings === | === Strings === | ||
Line 220: | Line 221: | ||
Ruby supports String literals as well. | Ruby supports String literals as well. | ||
− | < | + | {{code|text=<source lang="ruby"> |
>> "hello world" | >> "hello world" | ||
=> "hello world" | => "hello world" | ||
>> 'hello\nworld' | >> 'hello\nworld' | ||
=> "hello\\nworld" | => "hello\\nworld" | ||
+ | >> "2 + 2 = #{2 + 2}" # String embedding | ||
+ | => "2 + 2 = 4" | ||
>> %{one | >> %{one | ||
two | two | ||
three} | three} | ||
=> "one\ntwo\nthree" | => "one\ntwo\nthree" | ||
− | </ | + | </source>}} |
Strings are also Objects in Ruby: | Strings are also Objects in Ruby: | ||
− | < | + | {{code|text=<source lang="ruby"> |
>> "hello".reverse | >> "hello".reverse | ||
=> "olleh" | => "olleh" | ||
− | </ | + | </source>}} |
=== Symbols === | === Symbols === | ||
Line 242: | Line 245: | ||
Symbols are like Strings, but used for keywords or identifiers: | Symbols are like Strings, but used for keywords or identifiers: | ||
− | < | + | {{code|text=<source lang="ruby"> |
>> :verbose | >> :verbose | ||
=> :verbose | => :verbose | ||
Line 249: | Line 252: | ||
>> :verbose == :verbose | >> :verbose == :verbose | ||
=> true | => true | ||
− | </ | + | </source>}} |
+ | |||
+ | === Regular Expressions === | ||
+ | |||
+ | Ruby supports inline [[Regular_expressions|Regular Expressions]], or [http://rubydoc.info/stdlib/core/Regexp Regexps]. Regular Expressions can be used to match Strings: | ||
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
+ | >> "1-555-3333" =~ /(\d-)?\d{3}-\d{4}/ | ||
+ | => 0 | ||
+ | >> match = "Please call 1-555-3333".match(/(\d-)?\d{3}-\d{4}/) | ||
+ | => #<MatchData "1-555-3333" 1:"1-"> | ||
+ | >> match[0] | ||
+ | => "1-555-3333" | ||
+ | </source>}} | ||
+ | |||
+ | Regexps can also be used to rewrite Strings: | ||
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
+ | >> "hello world".gsub(/e/,'3').gsub(/o/,'0') | ||
+ | => "h3ll0 w0rld" | ||
+ | </source>}} | ||
=== Arrays === | === Arrays === | ||
Line 258: | Line 281: | ||
if you give Ruby a list of comma separated values inside brackets, Ruby will recgonize this as an array and use it as such from that point forward. | if you give Ruby a list of comma separated values inside brackets, Ruby will recgonize this as an array and use it as such from that point forward. | ||
− | < | + | {{code|text=<source lang="ruby"> |
>> my_array = [] | >> my_array = [] | ||
=> [] | => [] | ||
Line 273: | Line 296: | ||
>> filled_array = Array.new(5) { 0 } | >> filled_array = Array.new(5) { 0 } | ||
=> [0, 0, 0, 0, 0] | => [0, 0, 0, 0, 0] | ||
− | </ | + | </source>}} |
You will notice the item 'foo' is printed as "bar" because we defined this earlier in this page. | You will notice the item 'foo' is printed as "bar" because we defined this earlier in this page. | ||
Line 281: | Line 304: | ||
Ruby [http://rubydoc.info/stdlib/core/Hash Hashes] are similar to Arrays, except they require two objects for every item in the group. One of these objects is the 'key' and the other is the 'value'. | Ruby [http://rubydoc.info/stdlib/core/Hash Hashes] are similar to Arrays, except they require two objects for every item in the group. One of these objects is the 'key' and the other is the 'value'. | ||
This is very useful when you want to index items by some other than the array's zero-index. A hash also uses braces, instead of the brackets an array uses. | This is very useful when you want to index items by some other than the array's zero-index. A hash also uses braces, instead of the brackets an array uses. | ||
− | < | + | {{code|text=<source lang="ruby"> |
new_hash = { | new_hash = { | ||
:username => 'admin', | :username => 'admin', | ||
Line 289: | Line 312: | ||
:port => 22 | :port => 22 | ||
} | } | ||
− | </ | + | </source>}} |
You can use the key inside of brackets to return the value for that object. | You can use the key inside of brackets to return the value for that object. | ||
− | < | + | {{code|text=<source lang="ruby"> |
>> new_hash[:username] | >> new_hash[:username] | ||
=> 'admin' | => 'admin' | ||
− | </ | + | </source>}} |
Iterate through a hash, returning each key matched with it's value | Iterate through a hash, returning each key matched with it's value | ||
− | < | + | {{code|text=<source lang="ruby"> |
>> new_hash.each do |k, v| | >> new_hash.each do |k, v| | ||
>> puts "key: #{k}" | >> puts "key: #{k}" | ||
Line 314: | Line 337: | ||
value: letmein123 | value: letmein123 | ||
=> {:port=>22, :hostname=>"blackhatacademy.org", :service=>"ssh", :username=>"admin", :password=>"letmein123"} | => {:port=>22, :hostname=>"blackhatacademy.org", :service=>"ssh", :username=>"admin", :password=>"letmein123"} | ||
− | </ | + | </source>}} |
Hashes can also have default values: | Hashes can also have default values: | ||
− | < | + | {{code|text=<source lang="ruby"> |
>> counter = Hash.new(0) | >> counter = Hash.new(0) | ||
=> {} | => {} | ||
Line 338: | Line 361: | ||
>> md5s | >> md5s | ||
=> {"foo"=>"acbd18db4cc2f85cedef654fccc4a4d8", "bar"=>"37b51d194a7513e45b56f6524f2d51f2"} | => {"foo"=>"acbd18db4cc2f85cedef654fccc4a4d8", "bar"=>"37b51d194a7513e45b56f6524f2d51f2"} | ||
− | </ | + | </source>}} |
=== Casting === | === Casting === | ||
Line 351: | Line 374: | ||
* <kbd>to_set</kbd>: Converts an Object to a Set. | * <kbd>to_set</kbd>: Converts an Object to a Set. | ||
− | + | Ruby also provides top-level methods for coercing an Object into another type: | |
− | + | ||
− | + | {{code|text=<source lang="ruby"> | |
+ | >> Integer(1.5) | ||
+ | => 1 | ||
+ | >> Float(1) | ||
+ | => 1.0 | ||
+ | >> String(1.5) | ||
+ | => "1.5" | ||
+ | >> Array(1) | ||
+ | => [1] | ||
+ | >> Array(nil) | ||
+ | => [] | ||
+ | </source>}} | ||
− | < | + | == Operators == |
+ | |||
+ | === Boolean === | ||
+ | |||
+ | Ruby supports all the usual ANSI [[C]] boolean operators: | ||
+ | {{code|text=<source lang="ruby"> | ||
>> true && false # AND | >> true && false # AND | ||
=> false | => false | ||
Line 365: | Line 403: | ||
>> !true # NOT | >> !true # NOT | ||
=> false | => false | ||
− | </ | + | </source>}} |
− | = | + | The <kbd>&&</kbd>, <kbd>||</kbd>, <kbd>!</kbd> operators can also be used with non-Boolean values. In Ruby, everything is treated as <kbd>true</kbd>, except for <kbd>nil</kbd>. As a result of this, you can use the <kbd>||=</kbd> operator to lazily initialize variables: |
− | + | ||
− | + | ||
− | + | {{code|text=<source lang="ruby"> | |
+ | module Settings | ||
− | < | + | def self.path |
+ | @path ||= File.join(ENV['HOME'],'.foorc') | ||
+ | end | ||
+ | |||
+ | end | ||
+ | </source>}} | ||
+ | |||
+ | === Ternary Operator === | ||
+ | |||
+ | Ruby supports the ternary operator, just like ANSI [[C]]: | ||
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
+ | number >= 0 ? :integer : :negative | ||
+ | </source>}} | ||
+ | |||
+ | === Bitwise Manipulations === | ||
+ | {{main|Bitwise math}} | ||
+ | Ruby supports all of the common ANSI [[C]] bit-wise operators: | ||
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
>> 0xff & 0x02 # AND | >> 0xff & 0x02 # AND | ||
=> 2 | => 2 | ||
− | >> 0x02 | 0x1 # OR | + | >> 0x02 | 0x1 # OR |
=> 3 | => 3 | ||
− | >> 0x02 ^ 0x3 # XOR | + | >> 0x02 ^ 0x3 # XOR |
=> 1 | => 1 | ||
− | >> ~0x0 # inverse | + | >> ~0x0 # inverse |
=> -1 | => -1 | ||
− | >> 0x1 << 2 # left-shift | + | >> 0x1 << 2 # left-shift |
=> 4 | => 4 | ||
− | >> 0x3 >> 1 #right-shift | + | >> 0x3 >> 1 # right-shift |
=> 1 | => 1 | ||
− | </ | + | </source>}} |
+ | |||
+ | == Statements == | ||
+ | |||
+ | === If === | ||
+ | |||
+ | Like other scripting languages, Ruby supports <kbd>if</kbd> statements: | ||
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
+ | if x > 10 | ||
+ | puts 'greater than 10' | ||
+ | elsif x == 10 | ||
+ | puts 'equal to 10' | ||
+ | else | ||
+ | puts 'less than 10' | ||
+ | end | ||
+ | </source>}} | ||
+ | |||
+ | <kbd>if</kbd> statements can also be written as one-liners: | ||
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
+ | puts 'x is a negative number' if x < 0 | ||
+ | </source>}} | ||
+ | |||
+ | Ruby also provides an <kbd>unless</kbd> statement, which is equivalent to <kbd>if !expression</kbd>. | ||
+ | |||
+ | === Case === | ||
+ | |||
+ | === Begin === | ||
+ | |||
+ | === Rescue === | ||
+ | === Ensure === | ||
== Loops == | == Loops == | ||
Line 394: | Line 481: | ||
Ruby supports for loops like any other language: | Ruby supports for loops like any other language: | ||
− | < | + | {{code|text=<source lang="ruby"> |
>> for i in (1..10) | >> for i in (1..10) | ||
>> puts i | >> puts i | ||
Line 407: | Line 494: | ||
9 | 9 | ||
10 | 10 | ||
− | </ | + | </source>}} |
Generally, you never need to use for loops, due to Ruby's excellent support for Enumerators. | Generally, you never need to use for loops, due to Ruby's excellent support for Enumerators. | ||
Line 415: | Line 502: | ||
Ruby also supports traditional while loops: | Ruby also supports traditional while loops: | ||
− | < | + | {{code|text=<source lang="ruby"> |
>> queue = [1,2,3,4] | >> queue = [1,2,3,4] | ||
=> [1, 2, 3, 4] | => [1, 2, 3, 4] | ||
Line 425: | Line 512: | ||
3 | 3 | ||
4 | 4 | ||
− | </ | + | </source>}} |
=== Until === | === Until === | ||
Line 431: | Line 518: | ||
The <kbd>until</kbd> loop is a short-hand for saying <kbd>while !expression</kbd>: | The <kbd>until</kbd> loop is a short-hand for saying <kbd>while !expression</kbd>: | ||
− | < | + | {{code|text=<source lang="ruby"> |
>> queue = [1,2,3,4] | >> queue = [1,2,3,4] | ||
=> [1, 2, 3, 4] | => [1, 2, 3, 4] | ||
Line 441: | Line 528: | ||
3 | 3 | ||
4 | 4 | ||
− | </ | + | </source>}} |
=== Enumerators === | === Enumerators === | ||
Line 447: | Line 534: | ||
Ruby has superb support for Enumerators, or Iterators. | Ruby has superb support for Enumerators, or Iterators. | ||
− | < | + | {{code|text=<source lang="ruby"> |
>> (1..5).each { |i| puts i } | >> (1..5).each { |i| puts i } | ||
1 | 1 | ||
Line 455: | Line 542: | ||
5 | 5 | ||
=> 1..5 | => 1..5 | ||
− | >> (1..5).first(2) | + | >> (1..5).first(2) # get the first two integers |
=> [1, 2] | => [1, 2] | ||
− | >> (1..5).any? { |i| i % 2 == 0 } | + | >> (1..5).any? { |i| i % 2 == 0 } # are any even integers? |
=> true | => true | ||
− | >> (1..5).all? { |i| i < 10 } | + | >> (1..5).all? { |i| i < 10 } # are all integers less than 10? |
=> true | => true | ||
− | >> (1..5).select { |i| i % 2 == 0 } | + | >> (1..5).select { |i| i % 2 == 0 } # select only even integers |
=> [2, 4] | => [2, 4] | ||
− | >> (1..5).map { |i| i * 2 } | + | >> (1..5).map { |i| i * 2 } # multiply every integer by two |
=> [2, 4, 6, 8, 10] | => [2, 4, 6, 8, 10] | ||
− | </ | + | </source>}} |
These methods are defined by including the [http://rubydoc.info/stdlib/core/Enumerable Enumerable] module, and defining an <kbd>each</kbd> which enumerates over the elements of the Object: | These methods are defined by including the [http://rubydoc.info/stdlib/core/Enumerable Enumerable] module, and defining an <kbd>each</kbd> which enumerates over the elements of the Object: | ||
− | < | + | {{code|text=<source lang="ruby"> |
>> class PasswordBruter | >> class PasswordBruter | ||
>> include Enumerable | >> include Enumerable | ||
Line 493: | Line 580: | ||
hellx | hellx | ||
.... | .... | ||
+ | </source>}} | ||
+ | |||
+ | == Global Methods == | ||
+ | |||
+ | === defined? === | ||
+ | |||
+ | Checks if a Class, Module or Constant is defined: | ||
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
+ | if defined?(RUBY_ENGINE) | ||
+ | puts "Running on #{RUBY_ENGINE}" | ||
+ | end | ||
+ | </source>}} | ||
+ | |||
+ | === send === | ||
+ | |||
+ | Allows you to call arbitrary methods: | ||
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
+ | obj.send(method_name) | ||
+ | </source>}} | ||
+ | |||
+ | === throw / catch === | ||
+ | |||
+ | <kbd>throw</kbd> / <kbd>catch</kbd>: Throw and Catch allows one to jump out of a scope. This is similar to long jmp in Assembly: | ||
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
+ | def callback | ||
+ | catch(:abort, :success) do | ||
+ | puts 'yielding ...' | ||
+ | yield | ||
+ | puts 'completed!' | ||
+ | end | ||
+ | end | ||
+ | </source>}} | ||
+ | |||
+ | <pre> | ||
+ | >> callback { puts 'in the callback' } | ||
+ | yielding ... | ||
+ | in the callback | ||
+ | completed! | ||
+ | => :success | ||
+ | >> callback { puts 'aborting!'; throw :abort, :failed } | ||
+ | => :failed | ||
</pre> | </pre> | ||
+ | |||
+ | === raise === | ||
+ | |||
+ | Raises an exception: | ||
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
+ | >> raise("error!") | ||
+ | RuntimeError: error! | ||
+ | from (irb):38 | ||
+ | >> raise(ArgumentError,"invalid argument") | ||
+ | ArgumentError: invalid argument | ||
+ | from (irb):39 | ||
+ | </source>}} | ||
== User Input == | == User Input == | ||
Line 501: | Line 645: | ||
Ruby provides the <kbd>STDIN</kbd>, <kbd>STDOUT</kbd> and <kbd>STDERR</kbd> [http://rubydoc.info/stdlib/core/IO IO] constants. You can use these constants to read-input or print output. | Ruby provides the <kbd>STDIN</kbd>, <kbd>STDOUT</kbd> and <kbd>STDERR</kbd> [http://rubydoc.info/stdlib/core/IO IO] constants. You can use these constants to read-input or print output. | ||
− | < | + | {{code|text=<source lang="ruby"> |
STDOUT.print "Password: " | STDOUT.print "Password: " | ||
Line 512: | Line 656: | ||
puts "You entered: #{password}" | puts "You entered: #{password}" | ||
end | end | ||
− | </ | + | </source>}} |
As you've probably guess, top-level IO methods, such as <kbd>puts</kbd> and <kbd>readline</kbd>, simply call to <kbd>STDOUT</kbd> or <kbd>STDIN</kbd>. | As you've probably guess, top-level IO methods, such as <kbd>puts</kbd> and <kbd>readline</kbd>, simply call to <kbd>STDOUT</kbd> or <kbd>STDIN</kbd>. | ||
Line 522: | Line 666: | ||
All command-line arguments are exposed via the <kbd>ARGV</kbd> constant. | All command-line arguments are exposed via the <kbd>ARGV</kbd> constant. | ||
− | < | + | {{code|text=<source lang="ruby"> |
#!/usr/bin/env ruby | #!/usr/bin/env ruby | ||
puts "You passed the following arguments:" | puts "You passed the following arguments:" | ||
ARGV.each { |arg| puts " #{arg}" } | ARGV.each { |arg| puts " #{arg}" } | ||
− | </ | + | </source>}} |
Ruby also provides an <kbd>ARGF</kbd> which is the [http://rubydoc.info/stdlib/core/File File] for the first file-argument: | Ruby also provides an <kbd>ARGF</kbd> which is the [http://rubydoc.info/stdlib/core/File File] for the first file-argument: | ||
− | < | + | {{code|text=<source lang="ruby"> |
#!/usr/bin/env ruby | #!/usr/bin/env ruby | ||
Line 541: | Line 685: | ||
# ... | # ... | ||
end | end | ||
− | </ | + | </source>}} |
If you need to parse command-line options, use the built-in [http://rubydoc.info/stdlib/optparse/OptionParser OptionParser] library. | If you need to parse command-line options, use the built-in [http://rubydoc.info/stdlib/optparse/OptionParser OptionParser] library. | ||
+ | |||
+ | === Environment Variables === | ||
+ | |||
+ | You can access and set Environment Variables via the <kbd>ENV</kbd> Hash: | ||
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
+ | >> ENV['HOME'] | ||
+ | => "/home/blackhatacademy" | ||
+ | </source>}} | ||
== User-defined == | == User-defined == | ||
Line 606: | Line 759: | ||
{{code|text=<source lang="ruby"> | {{code|text=<source lang="ruby"> | ||
class MyClass | class MyClass | ||
+ | |||
+ | end | ||
+ | </source>}} | ||
+ | |||
+ | Classes can also inherit from other Classes: | ||
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
+ | class MyOtherClass < MyClass | ||
end | end | ||
Line 620: | Line 781: | ||
</source>}} | </source>}} | ||
+ | Reader/writer methods for variables can also be defined within the class: | ||
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
+ | class MyClass | ||
+ | |||
+ | # defines a foo method | ||
+ | attr_reader :foo | ||
+ | |||
+ | # defines a foo= method | ||
+ | attr_writer :bar | ||
+ | |||
+ | # defines foo and foo= methods | ||
+ | attr_accessor :baz | ||
+ | |||
+ | def initialize(foo,bar,baz) | ||
+ | @foo, @bar, @baz = foo, bar, baz | ||
+ | end | ||
+ | end | ||
+ | </source>}} | ||
=== Modules === | === Modules === | ||
+ | |||
+ | Modules are a way to group methods together, which can be included into multiple Classes. Modules allow you to compartmentalize common behaviours. | ||
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
+ | module HasName | ||
+ | attr_accessor :name | ||
+ | |||
+ | def initialize(name) | ||
+ | @name = name | ||
+ | end | ||
+ | |||
+ | def named?(other_name) | ||
+ | @name == other_name | ||
+ | end | ||
+ | |||
+ | def to_s | ||
+ | @name.to_s | ||
+ | end | ||
+ | |||
+ | end | ||
+ | |||
+ | class Person | ||
+ | |||
+ | include HasName | ||
+ | |||
+ | end | ||
+ | |||
+ | class Computer | ||
+ | |||
+ | include HasName | ||
+ | |||
+ | def initialize(ip,name) | ||
+ | @ip = ip | ||
+ | |||
+ | super(name) | ||
+ | end | ||
+ | |||
+ | end | ||
+ | </source>}} | ||
= Helpful Libraries = | = Helpful Libraries = | ||
+ | |||
+ | Ruby's [http://rubydoc.info/stdlib/ stdlib] provides many useful libraries. | ||
+ | |||
+ | === Struct === | ||
+ | |||
+ | [http://rubydoc.info/stdlib/core/Struct Struct] allows one to easily create Classes with specific attributes: | ||
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
+ | class Point < Struct.new(:x, :y) | ||
+ | end | ||
+ | </source>}} | ||
+ | |||
+ | <pre> | ||
+ | >> p1 = Point.new(10, 20) | ||
+ | => #<struct Point x=10, y=20> | ||
+ | >> p1.x | ||
+ | => 10 | ||
+ | >> p1.x += 20 | ||
+ | => 30 | ||
+ | </pre> | ||
+ | |||
+ | === OpenStruct === | ||
+ | |||
+ | [http://rubydoc.info/stdlib/ostruct/OpenStruct OpenStruct] is like Struct, but allows for arbitrary attributes: | ||
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
+ | >> require 'ostruct' | ||
+ | => true | ||
+ | >> config = OpenStruct.new | ||
+ | => #<OpenStruct> | ||
+ | >> config.x = 10 | ||
+ | => 10 | ||
+ | >> config.name = 'foo' | ||
+ | => "foo" | ||
+ | >> config.bla | ||
+ | => nil | ||
+ | </source>}} | ||
+ | |||
+ | === Set === | ||
+ | |||
+ | [http://rubydoc.info/stdlib/set/Set Set] is like an Array, but does not allow duplicates: | ||
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
+ | >> require 'set' | ||
+ | => true | ||
+ | >> s = Set[] | ||
+ | => #<Set: {}> | ||
+ | >> s << 1 | ||
+ | >> s << 2 | ||
+ | >> s << 2 | ||
+ | >> s << 3 | ||
+ | => #<Set: {1, 2, 3}> | ||
+ | </source>}} | ||
+ | |||
+ | === Base64 === | ||
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
+ | >> require 'base64' | ||
+ | => true | ||
+ | >> Base64.encode64("hello") | ||
+ | => "aGVsbG8=\n" | ||
+ | >> Base64.decode64("c2VjcmV0\n") | ||
+ | => "secret" | ||
+ | </source>}} | ||
+ | |||
+ | === Digest === | ||
+ | |||
+ | The [http://rubydoc.info/stdlib/digest Digest] module, provides classes for computing Cryptographic Hashes, such as MD5 and SHA256: | ||
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
+ | >> require 'digest/md5' | ||
+ | => true | ||
+ | >> Digest::MD5.hexdigest("hello") | ||
+ | => "5d41402abc4b2a76b9719d911017c592" | ||
+ | >> require 'digest/sha2' | ||
+ | => true | ||
+ | >> Digest::SHA256.file('linux.iso') | ||
+ | => "5a7eb8f97a196583530812132ef98fe9" | ||
+ | </source>}} | ||
+ | |||
+ | === JSON === | ||
+ | |||
+ | Ruby also provides a [http://rubydoc.info/stdlib/json JSON] serialization and parsing library: | ||
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
+ | >> require 'json' | ||
+ | => true | ||
+ | >> JSON.parse("[1,2]") | ||
+ | => [1, 2] | ||
+ | >> {1 => 2, 2 => 3}.to_json | ||
+ | => "{\"1\":2,\"2\":3}" | ||
+ | </source>}} | ||
+ | |||
+ | === Queue === | ||
+ | |||
=== Sockets === | === Sockets === | ||
− | + | Simple TCP server: | |
+ | |||
{{code|text=<source lang="ruby"> | {{code|text=<source lang="ruby"> | ||
require 'socket' | require 'socket' | ||
Line 639: | Line 954: | ||
</source>}} | </source>}} | ||
− | + | Simple TCP client: | |
+ | |||
{{code|text=<source lang="ruby"> | {{code|text=<source lang="ruby"> | ||
require 'socket' | require 'socket' | ||
Line 646: | Line 962: | ||
while line = client.gets # Read input from the socket connection | while line = client.gets # Read input from the socket connection | ||
− | puts line | + | puts line # Prints the input we captured with s.gets |
end | end | ||
Line 652: | Line 968: | ||
</source>}} | </source>}} | ||
− | == | + | === URI === |
− | === | + | |
− | === | + | The [http://rubydoc.info/stdlib/uri URI] library handles parsing and crafting of URIs: |
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
+ | >> require 'uri' | ||
+ | => true | ||
+ | >> uri = URI("http://www.blackhatlibrary.net/index.php?title=Ruby&action=edit§ion=42") | ||
+ | => #<URI::HTTP:0x000000010e2080 URL:http://www.blackhatlibrary.net/index.php?title=Ruby&action=edit§ion=42> | ||
+ | >> uri.host | ||
+ | => "www.blackhatlibrary.net" | ||
+ | >> uri.port | ||
+ | => 80 | ||
+ | >> uri.query | ||
+ | => "title=Ruby&action=edit§ion=42" | ||
+ | </source>}} | ||
+ | |||
+ | === Net::HTTP === | ||
+ | |||
+ | === open-uri === | ||
+ | |||
+ | [http://rubydoc.info/stdlib/open-uri/OpenURI open-uri] allows one to open URLs as temporary files: | ||
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
+ | >> require 'open-uri' | ||
+ | => true | ||
+ | >> page = open(URI("http://www.blackhatlibrary.net/")) | ||
+ | => #<File:/tmp/open-uri20120812-2361-143dlvc> | ||
+ | </source>}} | ||
+ | |||
== Gems == | == Gems == | ||
+ | |||
+ | Gems are packaged Ruby libraries and scripts. Anyone can create their [http://guides.rubygems.org/make-your-own-gem/ own gem] and publish it to https://rubygems.org. | ||
+ | |||
+ | Gems are installed using the <kbd>gem install</kbd>: | ||
+ | |||
+ | <pre>$ gem install foo-bar</pre> | ||
+ | |||
+ | Once installed, you can require the gem: | ||
+ | |||
+ | {{code|text=<source lang="ruby">require 'foo/bar'</source>}} | ||
+ | |||
+ | === Nokogiri === | ||
+ | |||
+ | [http://nokogiri.org/ Nokogiri] is a fast XML/[[HTML]] parser built ontop of libxml. | ||
+ | |||
+ | Installing on Debian / Ubuntu: | ||
+ | |||
+ | <pre>$ sudo apt-get install libxml2-dev libxslt1-dev | ||
+ | $ gem install nokogiri</pre> | ||
+ | |||
+ | Installing on RedHat / Fedora: | ||
+ | |||
+ | <pre>$ sudo yum install libxml2-devel libxslt-devel | ||
+ | $ gem install nokogiri</pre> | ||
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
+ | require 'nokogiri' | ||
+ | require 'open-uri' | ||
+ | |||
+ | doc = Nokogiri::HTML(open("http://www.reddit.com/")) | ||
+ | |||
+ | doc.search("div.entry a.title").each do |link| | ||
+ | puts link.attributes['href'] | ||
+ | end | ||
+ | </source>}} | ||
+ | |||
+ | === Sequel === | ||
+ | |||
+ | [http://sequel.rubyforge.org/ Sequel] is a low-level [[SQL]] library for '''Ruby'''. It allows you to query tables and insert data, all without having to write raw SQL. Sequel supports SQLite3, [[MySQL]], [[PostgreSQL]], [[Oracle]], etc. | ||
+ | |||
+ | Installing on Debian / Ubuntu: | ||
+ | |||
+ | <pre>$ sudo apt-get install libsqlite3-dev | ||
+ | $ gem install sqlite3-ruby sequel</pre> | ||
+ | |||
+ | Installing on RedHat / Fedora: | ||
+ | |||
+ | <pre>$ sudo yum install sqlite-devel | ||
+ | $ gem install sqlite3-ruby sequel</pre> | ||
+ | |||
+ | {{code|text=<source lang="ruby"> | ||
+ | require 'sequel' | ||
+ | |||
+ | DB = Sequel.sqlite('file.sqlite3') | ||
+ | DB.create_table(:mytable) do | ||
+ | integer: id | ||
+ | varchar: name, :length => 256 | ||
+ | end | ||
+ | |||
+ | DB[:mytable].insert(1, "foo") | ||
+ | DB[:mytable].insert(2, "bar") | ||
+ | DB[:mytable].where(:name => 'bar') | ||
+ | </source>}} | ||
+ | |||
+ | For more Sequel tips, please see the [http://sequel.rubyforge.org/rdoc/files/doc/cheat_sheet_rdoc.html Sequel Cheat Sheet]. | ||
+ | {{programming}} | ||
+ | {{social}} |
Latest revision as of 21:34, 14 October 2012
Ruby is an interpreted language, dynamically, reflective, semi-Functional and Object Orientated scripting language written in C. Ruby is said to be semi-Functional because it supports higher-order functions (aka lambdas) and closures (aka blocks). Ruby was created by Yukihiro "Matz" Matsumoto and was first released in 1995.
Matz's goal was to combine powerful features from various other programming languages, to create a programming language maximized for developer happiness; as opposed to computational efficiency. Ruby's Object Model mirrors that of Smalltalk, the syntax shares some similarities with Bash, Perl, Python, and the scoping rules for closures were taken from LISP.
Special thanks to Postmodern and Ohdazed for their contributions to this article.
Contents
Basics
Development Environment
- Installation
- Gems
Interactive Ruby Console
IRB, or the Interactive Ruby Console, comes bundled with Ruby and allows you to interactively run code right from your command line. IRB can be invoked from your terminal simply by typing 'irb'.
» irb --help Usage: irb.rb [options] [programfile] [arguments]
-f Suppress read of ~/.irbrc -m Bc mode (load mathn, fraction or matrix are available) -d Set $DEBUG to true (same as `ruby -d') -r load-module Same as `ruby -r' -I path Specify $LOAD_PATH directory --inspect Use `inspect' for output (default except for bc mode) --noinspect Don't use inspect for output --readline Use Readline extension module --noreadline Don't use Readline extension module --prompt prompt-mode --prompt-mode prompt-mode
Switch prompt mode. Pre-defined prompt modes are `default', `simple', `xmp' and `inf-ruby'
--inf-ruby-mode Use prompt appropriate for inf-ruby-mode on emacs.
Suppresses --readline.
--simple-prompt Simple prompt mode --noprompt No prompt mode --tracer Display trace for each execution of commands. --back-trace-limit n
Display backtrace top n and tail n. The default value is 16.
--irb_debug n Set internal debug level to n (not for popular use) -v, --version Print the version of irb
$ irb irb(main):001:0>puts 'woot' woot => nil irb(main):002:0>
Running irb --simple-prompt will provide you with a more basic looking Ruby shell.
$ irb --simple-prompt >> puts 'woot' woot => nil
You can use either 'exit', 'quit', or 'irb_exit' to close IRB and return to your terminal.
$ irb --simple-prompt >> exit $ # back in our terminal :D
RVM
RVM is a handy utility that can be used to manage multiple Ruby version installations on the same operating system. It allows you to run multiple interpreters and gemsets with a simple way to switch between them.
Pry
Pry is a Ruby gem that provides an alterative to IRB (Interactive Ruby Console) with additional functionality to dig down into Ruby code while you are coding. You can view the source-code of any Ruby method from within the interpreter. It also provides some cool extras like Gist integration, syntax highlighting, and command shell integration.
Pry Homepage: https://github.com/pry/pry/
Your first program
Code
#!/usr/bin/ruby puts "Hello world\n" |
Style
While Ruby is not whitespace sensitive, all Rubyists share a certain style:
- Indent code using two spaces.
- All code must be within 80 columns.
- Class/Module names must be capitialized and CamelCased.
- Constants must be UPPERCASED_AND_UNDERSCORED.
- Method/variable names must be in snake_case.
For a complete Ruby Style Guide, please see the GitHub Ruby Style Guide.
Explanation
Variables
Local
A local variable is a variable that can only be used within the block it was initialized in. It can be created by assigning an Object to a lowercase keyword.
foo = 'bar'
|
Global
Global variables can be accessed from anywhere within the entire program. They can be created by prefixing your variable the the $ symbol. Editting the assignment of a global variable will change the status of that variable globally and is generally avoided when writing Ruby scripts; use class-variables or constants instead.
$woot = 1337 |
Instance Variables
Instance variables begin with the '@' symbol. Accessing an uninitialzed instance will return the nil value.
>> @instance => nil >> @instance = 'ohdae' => "ohdae" |
Instance variables can also be defined at the Class/Module level:
>> module Settings >> @config = {:verbose => false} >> def self.config; @config; end >> end => Settings >> Settings.config => {:verbose => false} |
Class Variables
Class variables are shared by all methods within a Class or Module. These are created by using two '@' symbols at the beginning of your variable. Trying to initialize a class variable outside of a class will throw an error.
>> @@classvar NameError: uninitialized class variable @@classvar in Object from (irb):5 from :0 >> class Blackhat >> @@classvar = 'ohhai' >> def self.classvar; @@classvar; end >> end => Blackhat >> Blackhat.classvar => "ohhai" |
Predefined Variables
Certain variables are pre-defined into Ruby. The values of these variables cannot be changed.
- self: Represents the current scope. Similar to this from Java.
- nil: The null object.
- true: Boolean true.
- false: Boolean false.
Data Types
Boolean Values
Ruby defines two boolean values, true and false:
>> 1 == 1 => true >> 1 == 2 => false |
Integers
Ruby also provides Integer literals:
>> 10 => 10 >> 010 # octal => 8 >> 0x0a # hexadecimal => 10 >> 1_000_000 # short-hand for big values => 1000000 |
In Ruby, Integers are also Objects, which you can call methods on:
>> 0x42.chr => "A" |
Floats
Ruby also provides floating point decimal literals:
>> 1.5 => 1.5 >> 1.5e10 => 15000000000.0 |
Floats are also Objects:
>> 1.5.round => 2 |
Strings
Ruby supports String literals as well.
>> "hello world" => "hello world" >> 'hello\nworld' => "hello\\nworld" >> "2 + 2 = #{2 + 2}" # String embedding => "2 + 2 = 4" >> %{one two three} => "one\ntwo\nthree" |
Strings are also Objects in Ruby:
>> "hello".reverse => "olleh" |
Symbols
Symbols are like Strings, but used for keywords or identifiers:
>> :verbose => :verbose >> :verbose == 'verbose' => false >> :verbose == :verbose => true |
Regular Expressions
Ruby supports inline Regular Expressions, or Regexps. Regular Expressions can be used to match Strings:
>> "1-555-3333" =~ /(\d-)?\d{3}-\d{4}/ => 0 >> match = "Please call 1-555-3333".match(/(\d-)?\d{3}-\d{4}/) => #<MatchData "1-555-3333" 1:"1-"> >> match[0] => "1-555-3333" |
Regexps can also be used to rewrite Strings:
>> "hello world".gsub(/e/,'3').gsub(/o/,'0') => "h3ll0 w0rld" |
Arrays
An Array is a group of objects, very similar to lists in Python. The items or objects inside an array are indexed on a non-negative zero-index. The objects inside of a Ruby array can be any mixture of variables. Creating an array can be done in a few different ways. You do not need to specifically declare your variable as an array during initialization, for example if you give Ruby a list of comma separated values inside brackets, Ruby will recgonize this as an array and use it as such from that point forward.
>> my_array = [] => [] >> array_three = ["item", 5, foo, "Item2", "Strings can go here too"] => ["item", 5, "bar", "Item2", "Strings can go here too"] >> array_three[0] => "item" >> array_three[1] => 5 >> array_with_default = Array.new(1) => [] >> array_with_default[0] => 1 >> filled_array = Array.new(5) { 0 } => [0, 0, 0, 0, 0] |
You will notice the item 'foo' is printed as "bar" because we defined this earlier in this page.
Hashes or Associative Arrays
Ruby Hashes are similar to Arrays, except they require two objects for every item in the group. One of these objects is the 'key' and the other is the 'value'. This is very useful when you want to index items by some other than the array's zero-index. A hash also uses braces, instead of the brackets an array uses.
new_hash = { :username => 'admin', :password => 'letmein123', :hostname => 'blackhatacademy.org', :service => 'ssh' :port => 22 } |
You can use the key inside of brackets to return the value for that object.
>> new_hash[:username] => 'admin' |
Iterate through a hash, returning each key matched with it's value
>> new_hash.each do |k, v| >> puts "key: #{k}" >> puts "value: #{v}" >> end key: port value: 22 key: hostname value: blackhatacademy.org key: service value: ssh key: username value: admin key: password value: letmein123 => {:port=>22, :hostname=>"blackhatacademy.org", :service=>"ssh", :username=>"admin", :password=>"letmein123"} |
Hashes can also have default values:
>> counter = Hash.new(0) => {} >> counter[:foo] += 1 => 1 >> counter[:bar] += 2 => 2 >> counter => {:foo=>1, :bar=>2} >> require 'digest/md5' => true >> md5s = Hash.new { |hash,key| hash[key] = Digest::MD5.hexdigest(key) } => {} >> md5s['foo'] => "acbd18db4cc2f85cedef654fccc4a4d8" >> md5s['bar'] => "37b51d194a7513e45b56f6524f2d51f2" >> md5s => {"foo"=>"acbd18db4cc2f85cedef654fccc4a4d8", "bar"=>"37b51d194a7513e45b56f6524f2d51f2"} |
Casting
Ruby is a dynamically typed language, so it doesn't have Static Types or Type-Casting. Instead it has methods which convert an Object into another format:
- to_i: Converts an Object to an Integer.
- to_f: Converts an Object to a Float.
- to_s: Converts an Object to a String.
- to_sym: Converts an Object to a Symbol.
- to_a: Converts an Object to an Array.
- to_set: Converts an Object to a Set.
Ruby also provides top-level methods for coercing an Object into another type:
>> Integer(1.5) => 1 >> Float(1) => 1.0 >> String(1.5) => "1.5" >> Array(1) => [1] >> Array(nil) => [] |
Operators
Boolean
Ruby supports all the usual ANSI C boolean operators:
>> true && false # AND => false >> true || false # OR => true >> true ^ true # XOR => false >> !true # NOT => false |
The &&, ||, ! operators can also be used with non-Boolean values. In Ruby, everything is treated as true, except for nil. As a result of this, you can use the ||= operator to lazily initialize variables:
module Settings def self.path @path ||= File.join(ENV['HOME'],'.foorc') end end |
Ternary Operator
Ruby supports the ternary operator, just like ANSI C:
number >= 0 ? :integer : :negative |
Bitwise Manipulations
- Main article: Bitwise math
Ruby supports all of the common ANSI C bit-wise operators:
>> 0xff & 0x02 # AND => 2 >> 0x02 | 0x1 # OR => 3 >> 0x02 ^ 0x3 # XOR => 1 >> ~0x0 # inverse => -1 >> 0x1 << 2 # left-shift => 4 >> 0x3 >> 1 # right-shift => 1 |
Statements
If
Like other scripting languages, Ruby supports if statements:
if x > 10 puts 'greater than 10' elsif x == 10 puts 'equal to 10' else puts 'less than 10' end |
if statements can also be written as one-liners:
puts 'x is a negative number' if x < 0 |
Ruby also provides an unless statement, which is equivalent to if !expression.
Case
Begin
Rescue
Ensure
Loops
For
Ruby supports for loops like any other language:
>> for i in (1..10) >> puts i >> end 2 3 4 5 6 7 8 9 10 |
Generally, you never need to use for loops, due to Ruby's excellent support for Enumerators.
While
Ruby also supports traditional while loops:
>> queue = [1,2,3,4] => [1, 2, 3, 4] >> while (i = queue.shift) >> puts i >> end 1 2 3 4 |
Until
The until loop is a short-hand for saying while !expression:
>> queue = [1,2,3,4] => [1, 2, 3, 4] >> until queue.empty? >> puts queue.shift >> end 1 2 3 4 |
Enumerators
Ruby has superb support for Enumerators, or Iterators.
>> (1..5).each { |i| puts i } 1 2 3 4 5 => 1..5 >> (1..5).first(2) # get the first two integers => [1, 2] >> (1..5).any? { |i| i % 2 == 0 } # are any even integers? => true >> (1..5).all? { |i| i < 10 } # are all integers less than 10? => true >> (1..5).select { |i| i % 2 == 0 } # select only even integers => [2, 4] >> (1..5).map { |i| i * 2 } # multiply every integer by two => [2, 4, 6, 8, 10] |
These methods are defined by including the Enumerable module, and defining an each which enumerates over the elements of the Object:
>> class PasswordBruter >> include Enumerable >> def initialize(start_word) >> @start_word = start_word >> @end_word = ('x' * start_word.length) >> end >> def each >> (@start_word..@end_word).each { |word| yield word } >> end >> end => PasswordBruter >> PasswordBruter.new("hello").each { |word| puts word } hello hellp hellq hellr hells hellt hellu hellv hellw hellx .... |
Global Methods
defined?
Checks if a Class, Module or Constant is defined:
if defined?(RUBY_ENGINE) puts "Running on #{RUBY_ENGINE}" end |
send
Allows you to call arbitrary methods:
obj.send(method_name) |
throw / catch
throw / catch: Throw and Catch allows one to jump out of a scope. This is similar to long jmp in Assembly:
def callback catch(:abort, :success) do puts 'yielding ...' yield puts 'completed!' end end |
>> callback { puts 'in the callback' } yielding ... in the callback completed! => :success >> callback { puts 'aborting!'; throw :abort, :failed } => :failed
raise
Raises an exception:
>> raise("error!") RuntimeError: error! from (irb):38 >> raise(ArgumentError,"invalid argument") ArgumentError: invalid argument from (irb):39 |
User Input
STDIN / STDOUT / STDERR
Ruby provides the STDIN, STDOUT and STDERR IO constants. You can use these constants to read-input or print output.
STDOUT.print "Password: " password = STDIN.readline if password.length < 6 STDERR.puts "Password was too short!" exit -1 else puts "You entered: #{password}" end |
As you've probably guess, top-level IO methods, such as puts and readline, simply call to STDOUT or STDIN.
Ruby also provides the $stdin, $stdout, $stderr global variables, which allows you to hook/redirect all input/output. It's generally a good idea to use these global variables, instead of the constants.
Command-line Arguments
All command-line arguments are exposed via the ARGV constant.
#!/usr/bin/env ruby puts "You passed the following arguments:" ARGV.each { |arg| puts " #{arg}" } |
Ruby also provides an ARGF which is the File for the first file-argument:
#!/usr/bin/env ruby unless ARGV[0] $stderr.puts "usage: #{$0} FILE" exit -1 end ARGF.each_line do |line| # ... end |
If you need to parse command-line options, use the built-in OptionParser library.
Environment Variables
You can access and set Environment Variables via the ENV Hash:
>> ENV['HOME'] => "/home/blackhatacademy" |
User-defined
Methods
A simple hello world method:
def hello_world puts "Hello, World!" end |
When calling a method that takes an argument, the parenthesis around the argument are optional.
def hello(name) puts "Hello, #{name}!" end >> hello('ohdae') Hello, ohdae! => nil >> hello 'ohdae' Hello, ohdae! => nil |
Methods with default arguments:
def hello(name='ohdae') puts "Hello, #{name}!" end >> hello Hello, ohdae! => nil >> hello 'world' Hello, world! => nil |
Prematurely returning from a method:
def add(arg1, arg2) return nil unless arg1 return nil unless arg2 arg1.to_i + arg2.to_i end |
Note, that we don't have to specify a return on the last line of our add method. This is because in Ruby, every statement has a return value, and the last-statement of a method is it's default return value.
Classes
Classes have names which must start in capital letters.
class MyClass end |
Classes can also inherit from other Classes:
class MyOtherClass < MyClass end |
In Ruby, the constructor method is called initialize:
class MyClass def initialize puts "Hello\n" end end |
Reader/writer methods for variables can also be defined within the class:
class MyClass # defines a foo method attr_reader :foo # defines a foo= method attr_writer :bar # defines foo and foo= methods attr_accessor :baz def initialize(foo,bar,baz) @foo, @bar, @baz = foo, bar, baz end end |
Modules
Modules are a way to group methods together, which can be included into multiple Classes. Modules allow you to compartmentalize common behaviours.
module HasName attr_accessor :name def initialize(name) @name = name end def named?(other_name) @name == other_name end def to_s @name.to_s end end class Person include HasName end class Computer include HasName def initialize(ip,name) @ip = ip super(name) end end |
Helpful Libraries
Ruby's stdlib provides many useful libraries.
Struct
Struct allows one to easily create Classes with specific attributes:
class Point < Struct.new(:x, :y) end |
>> p1 = Point.new(10, 20) => #<struct Point x=10, y=20> >> p1.x => 10 >> p1.x += 20 => 30
OpenStruct
OpenStruct is like Struct, but allows for arbitrary attributes:
>> require 'ostruct' => true >> config = OpenStruct.new => #<OpenStruct> >> config.x = 10 => 10 >> config.name = 'foo' => "foo" >> config.bla => nil |
Set
Set is like an Array, but does not allow duplicates:
>> require 'set' => true >> s = Set[] => #<Set: {}> >> s << 1 >> s << 2 >> s << 2 >> s << 3 => #<Set: {1, 2, 3}> |
Base64
>> require 'base64' => true >> Base64.encode64("hello") => "aGVsbG8=\n" >> Base64.decode64("c2VjcmV0\n") => "secret" |
Digest
The Digest module, provides classes for computing Cryptographic Hashes, such as MD5 and SHA256:
>> require 'digest/md5' => true >> Digest::MD5.hexdigest("hello") => "5d41402abc4b2a76b9719d911017c592" >> require 'digest/sha2' => true >> Digest::SHA256.file('linux.iso') => "5a7eb8f97a196583530812132ef98fe9" |
JSON
Ruby also provides a JSON serialization and parsing library:
>> require 'json' => true >> JSON.parse("[1,2]") => [1, 2] >> {1 => 2, 2 => 3}.to_json => "{\"1\":2,\"2\":3}" |
Queue
Sockets
Simple TCP server:
require 'socket' server = TCPServer.new 4444 # Binds to TCP port 4444 loop do # Starts a loop to wait for connection client = server.accept # Receive and accept client connection client.puts "Hack The Planet!" # Send data to client client.close end |
Simple TCP client:
require 'socket' client = TCPSocket.new 'localhost', 4444 # Open TCP connection to localhost on port 4444 while line = client.gets # Read input from the socket connection puts line # Prints the input we captured with s.gets end client.close # Closes the socket |
URI
The URI library handles parsing and crafting of URIs:
>> require 'uri' => true >> uri = URI("http://www.blackhatlibrary.net/index.php?title=Ruby&action=edit§ion=42") => #<URI::HTTP:0x000000010e2080 URL:http://www.blackhatlibrary.net/index.php?title=Ruby&action=edit§ion=42> >> uri.host => "www.blackhatlibrary.net" >> uri.port => 80 >> uri.query => "title=Ruby&action=edit§ion=42" |
Net::HTTP
open-uri
open-uri allows one to open URLs as temporary files:
>> require 'open-uri' => true >> page = open(URI("http://www.blackhatlibrary.net/")) => #<File:/tmp/open-uri20120812-2361-143dlvc> |
Gems
Gems are packaged Ruby libraries and scripts. Anyone can create their own gem and publish it to https://rubygems.org.
Gems are installed using the gem install:
$ gem install foo-bar
Once installed, you can require the gem:
require 'foo/bar' |
Nokogiri
Nokogiri is a fast XML/HTML parser built ontop of libxml.
Installing on Debian / Ubuntu:
$ sudo apt-get install libxml2-dev libxslt1-dev $ gem install nokogiri
Installing on RedHat / Fedora:
$ sudo yum install libxml2-devel libxslt-devel $ gem install nokogiri
require 'nokogiri' require 'open-uri' doc = Nokogiri::HTML(open("http://www.reddit.com/")) doc.search("div.entry a.title").each do |link| puts link.attributes['href'] end |
Sequel
Sequel is a low-level SQL library for Ruby. It allows you to query tables and insert data, all without having to write raw SQL. Sequel supports SQLite3, MySQL, PostgreSQL, Oracle, etc.
Installing on Debian / Ubuntu:
$ sudo apt-get install libsqlite3-dev $ gem install sqlite3-ruby sequel
Installing on RedHat / Fedora:
$ sudo yum install sqlite-devel $ gem install sqlite3-ruby sequel
require 'sequel' DB = Sequel.sqlite('file.sqlite3') DB.create_table(:mytable) do integer: id varchar: name, :length => 256 end DB[:mytable].insert(1, "foo") DB[:mytable].insert(2, "bar") DB[:mytable].where(:name => 'bar') |
For more Sequel tips, please see the Sequel Cheat Sheet.