| 1 | {{{ |
| 2 | #!ruby |
| 3 | #!/usr/bin/env ruby |
| 4 | |
| 5 | $SAFE = 4 # set the security value at the highest prior unless we need more freedom |
| 6 | require 'a' # will load a.rb, only one time |
| 7 | load 'a.rb' # will load a.rb, every time called this line |
| 8 | |
| 9 | # |
| 10 | # Structure |
| 11 | # |
| 12 | |
| 13 | # Classes: |
| 14 | class Animal |
| 15 | # this sets a public id/varible that can be used for our objects, |
| 16 | # independently of being or not declared in the class, we can already use them |
| 17 | attr_accessor :lenght, :color # both read and write |
| 18 | attr_reader :lenght, :color # read-only |
| 19 | attr_writer :lenght, :color # write-only (setter) |
| 20 | |
| 21 | # this method will be called when creating a new object, it requires |
| 22 | # arguments if we state them |
| 23 | def initialize(given_name="Unknown", given_age) |
| 24 | |
| 25 | # the funny here is that if you call "dog = Animal.new(5)", it will |
| 26 | # understand that you are passing the second parameter and set Unknown |
| 27 | # to name automatically |
| 28 | @name = given_name # create variables for the objects that we can use, |
| 29 | # from the given arguments |
| 30 | @age = given_age |
| 31 | |
| 32 | # variables with @@ instead of @ are accessible only for classes as a |
| 33 | # whole, not by the instance of the objects, useful for store |
| 34 | # information relevant to all objects of the same class |
| 35 | if defined?(@@number_of_squares) |
| 36 | # variable already exists for all objects when the first one is created |
| 37 | @@number_of_squares += 1 |
| 38 | else |
| 39 | # create the variable first time when the first object is created |
| 40 | @@number_of_squares = 1 |
| 41 | end |
| 42 | end |
| 43 | |
| 44 | def self.count |
| 45 | @@number_of_squares # will return the number of objects when Animal.count is called |
| 46 | end |
| 47 | |
| 48 | # this is a simple method, used to perform actions to objects (like a function) |
| 49 | def name |
| 50 | # when calling "dog.name" will return "lassie" for example, "return" is optional |
| 51 | return @name |
| 52 | end |
| 53 | |
| 54 | # if you want to set the age in another moment than when initialized, you |
| 55 | # need to use this setter function |
| 56 | def age=(new_age) |
| 57 | # new_age is the parameter given to the call, like "dog.age = 10", |
| 58 | # adding = in the name of the method means that the method is used for |
| 59 | # assign values |
| 60 | @age = new_age |
| 61 | end |
| 62 | |
| 63 | def some_error_handled_case |
| 64 | # raise an error type with a message if a specific case |
| 65 | raise ArgumentError, "Age is too young" if @age < 2 |
| 66 | end |
| 67 | |
| 68 | # using self here is only accessible when calling the class, instead the |
| 69 | # object, like: Animal.show_name |
| 70 | def self.show_name # self acts like an alias to Animal, so: def Animal.show_name ... |
| 71 | puts self # when called, will print "Animal" (class name) |
| 72 | end |
| 73 | |
| 74 | # create an alias to whatever thing to another name |
| 75 | alias show_name list_name |
| 76 | |
| 77 | |
| 78 | private |
| 79 | # things from here only accessible from the object itself (instances) |
| 80 | # calls: method of an object can call its private methods (inside's class code) |
| 81 | # cannot call: dog.method_private |
| 82 | # note: using 'send' you can do it, it invokes methods by name: dog.send(:method_private) |
| 83 | def privated_area |
| 84 | puts "I will only be shown when another method of this class/object calls this private method" |
| 85 | end |
| 86 | |
| 87 | protected |
| 88 | # same as private, but callable from different objects of the same class |
| 89 | # allowing to communicate between them, like for do comparisons between objects |
| 90 | def age_difference_with(other_person) |
| 91 | (self.age - other_person.age).abs |
| 92 | end |
| 93 | # example: fred = Person.new(34) ; chris = Person.new(25) ; puts chris.age_difference_with(fred) |
| 94 | |
| 95 | def compare(c) |
| 96 | if c.age > age |
| 97 | "The other object's age is bigger." |
| 98 | else |
| 99 | "The other object's age is the same or smaller." |
| 100 | end |
| 101 | # example: chris = Person.new(25) ; marcos = Person.new(34) ; puts chris.compare_age(marcos) |
| 102 | end |
| 103 | |
| 104 | # back to the elements of code which are public |
| 105 | public |
| 106 | def summary |
| 107 | puts "I can be called normally" |
| 108 | end |
| 109 | |
| 110 | private :method1, :method2 # we can also define them on this way |
| 111 | end |
| 112 | |
| 113 | # Inheritance: |
| 114 | # create a superclass called Doctro from the Person's class (inheritance) |
| 115 | class Doctor < Person |
| 116 | # we have already defined the method "name" in the Person's class, so we extend it: |
| 117 | def name |
| 118 | # when we call .name method from a Doctor's object, will append like: "Dr. Name" |
| 119 | # "super" walks in inheritance of the same methods in their parents |
| 120 | "Dr. " + super |
| 121 | end |
| 122 | end |
| 123 | |
| 124 | somebody = Person.new("John") |
| 125 | puts somebody.name # John |
| 126 | who = Doctor.new("James") |
| 127 | puts who.name # Dr. James |
| 128 | puts who.instance_variables # @name |
| 129 | |
| 130 | |
| 131 | |
| 132 | # |
| 133 | # Polymorfism: |
| 134 | # - calling the method "talk" in Dogs or Cats they do different things, but |
| 135 | # you can use it in the same way this is very useful when you need to do the |
| 136 | # same action for different objects, for a example a loop of talking animals |
| 137 | # |
| 138 | class Dog < Animal |
| 139 | def talk |
| 140 | puts "Woof!" |
| 141 | end |
| 142 | end |
| 143 | |
| 144 | class Cat < Animal |
| 145 | def talk |
| 146 | puts "Meeew" |
| 147 | end |
| 148 | end |
| 149 | |
| 150 | |
| 151 | |
| 152 | # |
| 153 | # Nested classes: |
| 154 | # - useful for improve structure/grouping/dependency |
| 155 | # |
| 156 | class Drawing |
| 157 | class Line |
| 158 | end |
| 159 | |
| 160 | class Circle |
| 161 | end |
| 162 | |
| 163 | # you can call circle subclasses directly from Drawing too on this way: |
| 164 | def Drawing.give_me_a_circle |
| 165 | Circle.new |
| 166 | end |
| 167 | end |
| 168 | |
| 169 | # the way to call a class inside another class is by using :: |
| 170 | # trying to use directly Circle will fail, so: |
| 171 | my_circle = Drawing::Circle.new |
| 172 | |
| 173 | # |
| 174 | # Extensions |
| 175 | # - already-defined classes (any of them) can be extended or replaced for |
| 176 | # example to the Fixnum objects we can use .minutes to translate a number to |
| 177 | # minutes |
| 178 | class Fixnum |
| 179 | # we can extend any class with improvings or modifications |
| 180 | def minutes |
| 181 | self * 60 |
| 182 | end |
| 183 | end |
| 184 | # and so we can use now: |
| 185 | puts 5.minutes # 300 |
| 186 | |
| 187 | |
| 188 | # |
| 189 | # Modules |
| 190 | # |
| 191 | # They allows to separate things to avoid clashes, similar to classes, but |
| 192 | # they doesn't allows you to instantiate objects, their methods can be |
| 193 | # directly used without the need to create objects, they are more like |
| 194 | # functions that just processes things, let's say toolboxes of features |
| 195 | |
| 196 | module Country |
| 197 | class Ruler |
| 198 | attr_accessor :name |
| 199 | end |
| 200 | |
| 201 | def hello |
| 202 | puts "I can say hello without the need to create an object" |
| 203 | end |
| 204 | end |
| 205 | |
| 206 | module Toolbox |
| 207 | class Ruler |
| 208 | attr_accessor :lenght |
| 209 | end |
| 210 | |
| 211 | # Mix-in: this will print the name of the class which loaded this module |
| 212 | # useful for introducing methods in other's classes |
| 213 | # |
| 214 | # basically is a method defined outside of any class form, so when |
| 215 | # integrating a module inside an external class it will simply work on it |
| 216 | def class_name |
| 217 | self.class.to_s |
| 218 | end |
| 219 | end |
| 220 | |
| 221 | # direct call of the module with its contents |
| 222 | a = Toolbox::Ruler.new |
| 223 | a.lenght = 50 |
| 224 | b = Country::Ruler.new |
| 225 | b.name = "Ghengis Khan" |
| 226 | |
| 227 | # get the module features and directly use it |
| 228 | include Country |
| 229 | governor = Ruler.new |
| 230 | |
| 231 | # you can use the method hello from the module Country, without the need to |
| 232 | # create or use of objects |
| 233 | hello |
| 234 | |
| 235 | # |
| 236 | # Flow examples |
| 237 | # |
| 238 | |
| 239 | # loops |
| 240 | loop do |
| 241 | i += 1 |
| 242 | break if i > 100 # break da loop |
| 243 | end |
| 244 | |
| 245 | while (i == 10) |
| 246 | puts "i = 10" |
| 247 | end |
| 248 | |
| 249 | until (i > 10) |
| 250 | puts "i finally reached 10" |
| 251 | end |
| 252 | |
| 253 | |
| 254 | # if |
| 255 | if 2 == 1 |
| 256 | puts "universe is broken" |
| 257 | end |
| 258 | |
| 259 | unless 2 == 2 |
| 260 | puts "universe is broken" |
| 261 | end |
| 262 | |
| 263 | # case |
| 264 | fruit = "orange" |
| 265 | case fruit |
| 266 | when "orange" |
| 267 | color = "orange" |
| 268 | when "apple" |
| 269 | color = "green" |
| 270 | else |
| 271 | color "unknown" |
| 272 | end |
| 273 | |
| 274 | # ternary operator |
| 275 | puts x > 10 ? "higher than 10" : "lower or equal to 10" |
| 276 | |
| 277 | |
| 278 | |
| 279 | # |
| 280 | # Structures: |
| 281 | # it is an easy and fast way to define attributes and hold data, same as to |
| 282 | # create an entire class with defined initializators (but without require |
| 283 | # strictly to set all the parameters) |
| 284 | Person = Struct.new(:name, :gender, :age) |
| 285 | fred = Person.new("Fred", "male", 50) |
| 286 | |
| 287 | |
| 288 | |
| 289 | # variable substitution ways: |
| 290 | foo = "12345678901234567890" |
| 291 | # puts the first 10 chars in different ways: |
| 292 | puts foo[1,10] |
| 293 | puts foo[0..9] |
| 294 | puts foo.slice(0,10) |
| 295 | puts foo.match("^..........").to_s |
| 296 | |
| 297 | |
| 298 | # Arrays: |
| 299 | a = [1, 2, 3, "four"] |
| 300 | a << 5 |
| 301 | a.push 6 |
| 302 | puts a.empty? # false |
| 303 | puts a.include?("four") # true |
| 304 | |
| 305 | # Hashes (associative arrays) |
| 306 | dictionary = { 'cat' => 'feline animal', |
| 307 | 'dog' => 'canine animal', |
| 308 | 'tags' => ['books', |
| 309 | 'libraries', |
| 310 | 'knowledge'] } |
| 311 | puts dictionary['cat'] # shows description |
| 312 | puts dictionary['tags'].first # shows the first array element for the subarray tags |
| 313 | dictionary.delete("cat") |
| 314 | dictionary.delete_if { |key, value| value =~ /feline/ } |
| 315 | |
| 316 | |
| 317 | # Code blocks |
| 318 | def each_vowel |
| 319 | %w{a e i o u}.each { |vowel| yield vowel } |
| 320 | end |
| 321 | |
| 322 | each_vowel { |v| puts v + " is a vowel" } |
| 323 | # the delimiter of "each" can be modified passing an argument like .each(',') or |
| 324 | # changing the input delimiter variable $/ |
| 325 | |
| 326 | |
| 327 | |
| 328 | # |
| 329 | # Errors handling |
| 330 | # |
| 331 | class GetWeb |
| 332 | begin |
| 333 | # block of code where can happen errors |
| 334 | a = (10 / 0) # if this doesn't works... |
| 335 | rescue => e |
| 336 | a = 10 # let's still use the original value in failed cases, instead of exit/error |
| 337 | puts "class of exception is: " + e.class.to_s |
| 338 | end |
| 339 | end |
| 340 | |
| 341 | # another example: |
| 342 | data = "" |
| 343 | begin |
| 344 | #<..code to retrieve the contents of a Web page..> |
| 345 | #data = <..content of Web page..> |
| 346 | rescue ZeroDivisionError |
| 347 | #... code to rescue the zero division exception here ... |
| 348 | rescue YourOwnException |
| 349 | #... code to rescue a different type of exception here ... |
| 350 | rescue |
| 351 | puts "The Web page could not be loaded! Using default data instead." |
| 352 | #data = <..load data from local file..> |
| 353 | end |
| 354 | puts data |
| 355 | |
| 356 | |
| 357 | # If you want to run a script in debug mode, "ruby -r debug script.rb", use |
| 358 | # step, break, watch, cont, etc... |
| 359 | |
| 360 | |
| 361 | |
| 362 | # Catch & Throw: |
| 363 | # note: catch & throw is useless and confusing, avoid it |
| 364 | # catch & throw works in a similar way as rescue/raise, but using symbols rather than exceptions |
| 365 | catch(:finish) do |
| 366 | 1000.times do |
| 367 | x = rand(1000) |
| 368 | # we will exit the loop "catch" containing the symbol :finish if we got this case |
| 369 | throw :finish if x == 123 |
| 370 | end |
| 371 | |
| 372 | puts "Generated 1000 random numbers withoutgenerating 123!" |
| 373 | end |
| 374 | |
| 375 | # another catch & throw example |
| 376 | def routine(n) |
| 377 | puts n # final result will produce: 3 2 1 0 |
| 378 | throw :done if n <= 0 # exit inifite nested loop if case happens |
| 379 | routine(n-1) # nested itself, infinitely |
| 380 | end |
| 381 | |
| 382 | catch(:done) { routine(3) } |
| 383 | |
| 384 | |
| 385 | # |
| 386 | # Dynamic Code Execution |
| 387 | # |
| 388 | |
| 389 | # executes the code created dynamically |
| 390 | eval "puts 2 + 2" |
| 391 | |
| 392 | # similar: |
| 393 | my_number = 15 |
| 394 | my_code = %Q{#{my_number} * 2} |
| 395 | puts eval(my_code) |
| 396 | |
| 397 | # String interpolation makes the eval methods powerful tools for generating |
| 398 | # different features on the fly. This ability is a power unseen in the majority |
| 399 | # of programming languages |
| 400 | # - this method adds an accessor to another class, |
| 401 | # dynamically using class_eval and interpolating a name given externally |
| 402 | def add_accessor_to_person(accessor_name) |
| 403 | Person.class_eval %Q{ |
| 404 | attr_accessor :#{accessor_name} |
| 405 | } |
| 406 | end |
| 407 | |
| 408 | # It’s possible to take the previous example a lot further and add an |
| 409 | # add_accessor method to every class by putting your class_eval cleverness in a |
| 410 | # new method, defined within the Class class (from which all other classes descend): |
| 411 | class Class |
| 412 | def add_accessor(accessor_name) |
| 413 | self.class_eval %Q{ |
| 414 | attr_accessor :#{accessor_name} |
| 415 | } |
| 416 | end |
| 417 | end |
| 418 | |
| 419 | # You can eval code in instances of objects too: |
| 420 | class MyClass |
| 421 | def initialize |
| 422 | @my_variable = 'Hello, world!' |
| 423 | end |
| 424 | end |
| 425 | |
| 426 | obj = MyClass.new |
| 427 | obj.instance_eval { puts @my_variable } # add extra code to an existing object and execute it |
| 428 | |
| 429 | # In the same way you can define methods for existing objects |
| 430 | obj.instance_eval do def new_method ; puts 'born new method in an alive object' ; end ; end |
| 431 | # better way to define a method for an existing object, if you dont want to use |
| 432 | # dynamic code execution of eval |
| 433 | obj.new_method do def new_method ; puts 'born new method in an alive object' ; end ; end |
| 434 | |
| 435 | |
| 436 | |
| 437 | # example of an "attr_accessor" equivalent writed in dynamic code, which will work in the same way: |
| 438 | class Class |
| 439 | def add_accessor(accessor_name) |
| 440 | self.class_eval %Q{ |
| 441 | def #{accessor_name} |
| 442 | @#{accessor_name} |
| 443 | end |
| 444 | def #{accessor_name}=(value) |
| 445 | @#{accessor_name} = value |
| 446 | end |
| 447 | } |
| 448 | end |
| 449 | end |
| 450 | |
| 451 | # You can use this technique to create a multitude of different “code |
| 452 | # generators” and methods that can act as a “macro” language to perform things |
| 453 | # in Ruby that are otherwise lengthy to type out. |
| 454 | |
| 455 | |
| 456 | |
| 457 | # |
| 458 | # Forks & Processes |
| 459 | # |
| 460 | |
| 461 | # process-ID is returned in the parent but 'nil' in the child, use this to |
| 462 | # determine which process a script is in |
| 463 | if fork.nil? |
| 464 | exec "ruby other-file.rb" |
| 465 | end |
| 466 | |
| 467 | # fork a child and wait for it |
| 468 | child = fork do |
| 469 | sleep 3 |
| 470 | puts "Child says 'hi'!" |
| 471 | end |
| 472 | puts "Waiting for the child process..." |
| 473 | Process.wait child |
| 474 | puts "All done!" |
| 475 | |
| 476 | |
| 477 | |
| 478 | |
| 479 | |
| 480 | |
| 481 | |
| 482 | |
| 483 | # |
| 484 | # Unit Testing |
| 485 | # |
| 486 | # - default in stdlib is Minitest, but there's also: rspec, minitest, |
| 487 | # test/unit, minispec, bacon, testrocket... rspec is also very used |
| 488 | |
| 489 | # create a method for test it later |
| 490 | class String |
| 491 | def titleize |
| 492 | # we want to use this method for print results like: "This Is A Test" |
| 493 | self.capitalize |
| 494 | # and we will end later in improving the code like these next commented |
| 495 | # lines, because we haven see that the previous test failed in some cases |
| 496 | #self.gsub(/\b\w/) {|letter| letter.upcase } |
| 497 | #self.gsub(/\s\w/) {|letter| letter.upcase } |
| 498 | #self.gsub(/(\A|\s)\w/) {|letter| letter.upcase } |
| 499 | end |
| 500 | end |
| 501 | |
| 502 | puts "this is a test".titleize # this will print "This is a test", but we don't want this result, so for avoid bugs: |
| 503 | |
| 504 | # method 1 for testing (manual testing) |
| 505 | # let's add some "assertion" checkers |
| 506 | # |
| 507 | # if our method doesn't give us what we exactly expect, fail |
| 508 | raise "Fail 1" unless "this is a test".titleize == "This Is A Test" |
| 509 | # what happens with numbers? let's add this because this is what we expect in any case |
| 510 | raise "Fail 2" unless "another test 1234".titleize == "Another Test 1234" |
| 511 | # and with other chars like ' ? |
| 512 | raise "Fail 2" unless "We're testing titleize".titleize == "We're Testing Titleize" |
| 513 | |
| 514 | # method 2 for testing |
| 515 | require 'test/unit' |
| 516 | # there's also "Minitest" (included in stdlib) and "Bacon" for unit testing |
| 517 | class TestTitleize < Test::Unit::TestCase |
| 518 | def test_basic |
| 519 | assert_equal("This Is A Test", "this is a test".titleize) |
| 520 | assert_equal("Another Test 1234", "another test 1234".titleize) |
| 521 | assert_equal("We're Testing", "we're testing".titleize) |
| 522 | end |
| 523 | end |
| 524 | |
| 525 | # method 3 for testing: use Minitest instead, seems like more easier and fast to use option |
| 526 | module DataStore::AdapterSpec |
| 527 | it "returns nil for an invalid key" do |
| 528 | @adapter.get(:invalid).must_equal nil |
| 529 | end |
| 530 | |
| 531 | it "can set a value" do |
| 532 | @adapter.set(:foo, 42) |
| 533 | @adapter.get(:foo).must_equal 42 |
| 534 | end |
| 535 | end |
| 536 | # from: http://wojtekmach.pl/blog/2013/07/17/sharing-examples-in-minitest/ |
| 537 | # more: http://blog.arvidandersson.se/2012/03/28/minimalicous-testing-in-ruby-1-9 |
| 538 | |
| 539 | |
| 540 | |
| 541 | # |
| 542 | # Misc |
| 543 | # |
| 544 | # run when finish |
| 545 | at_exit { puts "#{Dir.pwd}" } # enqueue a job for when the application has finished to run |
| 546 | # trap |
| 547 | trap("SIGINT") do |
| 548 | puts "signal INT trapped!, what we should do?" |
| 549 | end |
| 550 | |
| 551 | |
| 552 | # Using Files |
| 553 | puts "It exists" if File.exist?("text.txt") |
| 554 | |
| 555 | File.open("text.txt") { |f| puts f.gets } # show file contents (cat) |
| 556 | |
| 557 | f = File.new("text.txt", "r") |
| 558 | puts f.gets |
| 559 | f.close |
| 560 | |
| 561 | data = File.read("text.txt") |
| 562 | array_of_lines = File.readlines("text.txt") |
| 563 | |
| 564 | f = File.open("text.txt") |
| 565 | puts f.gets |
| 566 | puts "position in file is: " + f.pos |
| 567 | f.pos = 8 |
| 568 | puts "position in file has moved to: " + f.pos |
| 569 | |
| 570 | # by using File.open in a block, is not needed to close the file when finish |
| 571 | File.open("text.txt", "w") do |entry| entry.puts "Hi" end |
| 572 | # note that the next line is invalid, if you put a space before ( then is not an argument list what you pass to it |
| 573 | #File.open ("text.txt", "w") do |entry| entry.puts "Hi" end |
| 574 | |
| 575 | # appending |
| 576 | f = File.open "text.txt", "a" |
| 577 | f.puts Time.now |
| 578 | f.close |
| 579 | |
| 580 | # See the modified time of a file |
| 581 | f = File.mtime "text.txt" |
| 582 | puts f.hour # since the object returned (f) is a Time object, we can treat him as it |
| 583 | |
| 584 | |
| 585 | # |
| 586 | # Docs |
| 587 | # |
| 588 | # In documentations, "Array#sample" means the instance method of a class |
| 589 | |
| 590 | #= RDoc Example |
| 591 | # |
| 592 | #== This is a heading |
| 593 | # |
| 594 | #* First item in an outer list |
| 595 | # * First item in an inner list |
| 596 | # * Second item in an inner list |
| 597 | #* Second item in an outer list |
| 598 | # * Only item in this inner list |
| 599 | # |
| 600 | #== This is a second heading |
| 601 | # |
| 602 | #Visit www.rubyinside.com |
| 603 | # |
| 604 | #== Test of text formatting features |
| 605 | # |
| 606 | #Want to see *bold* or _italic_ text? You can even embed |
| 607 | #+text that looks like code+ by surrounding it with plus |
| 608 | #symbols. Indented code will be automatically formatted: |
| 609 | # |
| 610 | # class MyClass |
| 611 | # def method_name |
| 612 | # puts "test" |
| 613 | # end |
| 614 | # end |
| 615 | # |
| 616 | #-- |
| 617 | # This section is hidden from RDoc and could contain developer |
| 618 | # notes, private messages between developers, etc. |
| 619 | #++ |
| 620 | # RDoc begins processing again here after the ++. |
| 621 | # |
| 622 | |
| 623 | # run "rdoc file.rb" to generate the documentation |
| 624 | # by adding in a class or element "#:nodoc: all" there's no docs generated (for |
| 625 | # the entire class) |
| 626 | |
| 627 | |
| 628 | |
| 629 | # |
| 630 | # Debug |
| 631 | # |
| 632 | # - ruby -d foo.rb: see page 190 of "begining ruby" which has some basic demo |
| 633 | |
| 634 | |
| 635 | # SAFE levels |
| 636 | # |
| 637 | # Value of $SAFE Description |
| 638 | # 0 No restrictions. This is the default safe level. |
| 639 | # 1 Potentially unsafe methods can’t use tainted data. Also, the current |
| 640 | # directory is not added to Ruby’s search path for loading libraries. |
| 641 | # 2 The restrictions of safe level 1, plus Ruby won’t load any external |
| 642 | # program files from globally writable locations in the filesystem. This is to |
| 643 | # prevent attacks where hackers upload malicious code and manipulate existing |
| 644 | # programs to load them. Some potentially dangerous methods are also |
| 645 | # deactivated, such as File#chmod, Kernel#fork, and Process::setpriority. |
| 646 | # 3 The restrictions of level 2, plus newly created objects within the |
| 647 | # program are considered tainted automatically. You also cannot untaint objects. |
| 648 | # 4 The restrictions of level 3, plus nontainted objects created prior to |
| 649 | # the safe level being set cannot be modified. You can use this to set up an |
| 650 | # execution environ- ment in a lower safe mode, and then provide a way to |
| 651 | # continue execution while protecting the original objects and environment. |
| 652 | |
| 653 | |
| 654 | |
| 655 | |
| 656 | |
| 657 | # |
| 658 | # MORE: |
| 659 | # |
| 660 | # regex: |
| 661 | # Try regular expressions in realtime! http://rubular.com/ |
| 662 | # |
| 663 | # references: |
| 664 | # http://www.zenspider.com/Languages/Ruby/QuickRef.html |
| 665 | # http://www.tutorialspoint.com/ruby/ruby_quick_guide.htm |
| 666 | # "Begining Ruby - book": useful classes and methods, errors, regex, variables, etc... from pag. 575 |
| 667 | # |
| 668 | # standard lib: |
| 669 | # http://www.ruby-doc.org/stdlib-2.1.0/ |
| 670 | |
| 671 | }}} |
| 672 | |