Changes between Initial Version and Version 1 of SummaryRuby


Ignore:
Timestamp:
Jan 11, 2014, 4:39:53 PM (11 years ago)
Author:
Thanatermesis
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • SummaryRuby

    v1 v1  
     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
     6require 'a'  # will load a.rb, only one time
     7load 'a.rb'  # will load a.rb, every time called this line
     8
     9#
     10# Structure
     11#
     12
     13# Classes:
     14class 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
     111end
     112
     113# Inheritance:
     114# create a superclass called Doctro from the Person's class (inheritance)
     115class 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
     122end
     123
     124somebody = Person.new("John")
     125puts somebody.name # John
     126who = Doctor.new("James")
     127puts who.name # Dr. James
     128puts 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#
     138class Dog < Animal
     139    def talk
     140        puts "Woof!"
     141    end
     142end
     143
     144class Cat < Animal
     145    def talk
     146        puts "Meeew"
     147    end
     148end
     149
     150
     151
     152#
     153# Nested classes:
     154#   - useful for improve structure/grouping/dependency
     155#
     156class 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
     167end
     168
     169# the way to call a class inside another class is by using ::
     170# trying to use directly Circle will fail, so:
     171my_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
     178class Fixnum
     179    # we can extend any class with improvings or modifications
     180    def minutes
     181        self * 60
     182    end
     183end
     184# and so we can use now:
     185puts 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
     196module 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
     204end
     205
     206module 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
     219end
     220
     221# direct call of the module with its contents
     222a = Toolbox::Ruler.new
     223a.lenght = 50
     224b = Country::Ruler.new
     225b.name = "Ghengis Khan"
     226
     227# get the module features and directly use it
     228include Country
     229governor = Ruler.new
     230
     231# you can use the method hello from the module Country, without the need to
     232# create or use of objects
     233hello
     234
     235#
     236# Flow examples
     237#
     238
     239# loops
     240loop do
     241    i += 1
     242    break if i > 100  # break da loop
     243end
     244
     245while (i == 10)
     246    puts "i = 10"
     247end
     248
     249until (i > 10)
     250    puts "i finally reached 10"
     251end
     252
     253
     254# if
     255if 2 == 1
     256    puts "universe is broken"
     257end
     258
     259unless 2 == 2
     260    puts "universe is broken"
     261end
     262
     263# case
     264fruit = "orange"
     265case fruit
     266    when "orange"
     267        color = "orange"
     268    when "apple"
     269        color = "green"
     270    else
     271        color "unknown"
     272end
     273
     274# ternary operator
     275puts  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)
     284Person = Struct.new(:name, :gender, :age)
     285fred = Person.new("Fred", "male", 50)
     286
     287
     288
     289# variable substitution ways:
     290foo = "12345678901234567890"
     291# puts the first 10 chars in different ways:
     292puts foo[1,10]
     293puts foo[0..9]
     294puts foo.slice(0,10)
     295puts foo.match("^..........").to_s
     296
     297
     298# Arrays:
     299a = [1, 2, 3, "four"]
     300a << 5
     301a.push 6
     302puts a.empty? # false
     303puts a.include?("four") # true
     304
     305# Hashes (associative arrays)
     306dictionary = { 'cat' => 'feline animal',
     307               'dog' => 'canine animal',
     308               'tags' => ['books',
     309                   'libraries',
     310                   'knowledge'] }
     311puts dictionary['cat'] # shows description
     312puts dictionary['tags'].first # shows the first array element for the subarray tags
     313dictionary.delete("cat")
     314dictionary.delete_if { |key, value| value =~ /feline/ }
     315
     316
     317# Code blocks
     318def each_vowel
     319    %w{a e i o u}.each { |vowel| yield vowel }
     320end
     321
     322each_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#
     331class 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
     339end
     340
     341# another example:
     342data = ""
     343begin
     344    #<..code to retrieve the contents of a Web page..>
     345    #data = <..content of Web page..>
     346rescue ZeroDivisionError
     347    #... code to rescue the zero division exception here ...
     348rescue YourOwnException
     349    #... code to rescue a different type of exception here ...
     350rescue
     351    puts "The Web page could not be loaded! Using default data instead."
     352    #data = <..load data from local file..>
     353end
     354puts 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
     365catch(: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!"
     373end
     374
     375# another catch & throw example
     376def 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
     380end
     381
     382catch(:done) { routine(3) }
     383
     384
     385#
     386# Dynamic Code Execution
     387#
     388
     389# executes the code created dynamically
     390eval "puts 2 + 2"
     391
     392# similar:
     393my_number = 15
     394my_code = %Q{#{my_number} * 2}
     395puts 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
     402def add_accessor_to_person(accessor_name)
     403    Person.class_eval %Q{
     404    attr_accessor :#{accessor_name}
     405    }
     406end
     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):
     411class Class
     412    def add_accessor(accessor_name)
     413        self.class_eval %Q{
     414            attr_accessor :#{accessor_name}
     415        }
     416    end
     417end
     418
     419# You can eval code in instances of objects too:
     420class MyClass
     421    def initialize
     422        @my_variable = 'Hello, world!'
     423    end
     424end
     425
     426obj = MyClass.new
     427obj.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
     430obj.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
     433obj.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:
     438class 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
     449end
     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
     463if fork.nil?
     464    exec "ruby other-file.rb"
     465end
     466
     467# fork a child and wait for it
     468child = fork do
     469    sleep 3
     470    puts "Child says 'hi'!"
     471end
     472puts "Waiting for the child process..."
     473Process.wait child
     474puts "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
     490class 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
     500end
     501
     502puts "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
     508raise "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
     510raise "Fail 2" unless "another test 1234".titleize      == "Another Test 1234"
     511# and with other chars like ' ?
     512raise "Fail 2" unless "We're testing titleize".titleize == "We're Testing Titleize"
     513
     514# method 2 for testing
     515require 'test/unit'
     516# there's also "Minitest" (included in stdlib) and "Bacon" for unit testing
     517class 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
     523end
     524
     525# method 3 for testing: use Minitest instead, seems like more easier and fast to use option
     526module 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
     535end
     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
     545at_exit { puts "#{Dir.pwd}" } # enqueue a job for when the application has finished to run
     546# trap
     547trap("SIGINT") do
     548    puts "signal INT trapped!, what we should do?"
     549end
     550
     551
     552# Using Files
     553puts "It exists" if File.exist?("text.txt")
     554
     555File.open("text.txt") { |f| puts f.gets }  # show file contents (cat)
     556
     557f = File.new("text.txt", "r")
     558puts f.gets
     559f.close
     560
     561data = File.read("text.txt")
     562array_of_lines = File.readlines("text.txt")
     563
     564f = File.open("text.txt")
     565puts f.gets
     566puts "position in file is: " + f.pos
     567f.pos = 8
     568puts "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
     571File.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
     576f = File.open "text.txt", "a"
     577f.puts Time.now
     578f.close
     579
     580# See the modified time of a file
     581f = File.mtime "text.txt"
     582puts 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