====== Introduction to Ruby ====== ==== "A Programmer's Best Friend" ==== ---- ===== Ruby ===== * Creator: Yukihiro Matsumoto * Introduced: 1995 * Open source * Installable package on many UNIX/Linux systems * Windows installer obtainable from http://www.ruby-lang.org * For macOS, installing Ruby through homebrew is recommended: https://www.ruby-lang.org/en/documentation/installation/#homebrew * Can be used for tasks that other dynamic programming languages are used for. * Initially gained a following due to the popularity of the [[https://wikiless.tiekoetter.com/wiki/Ruby_on_Rails | Ruby on Rails]] web application framework. * Used by major projects such as [[https://wikiless.tiekoetter.com/wiki/GitLab | GitLab]], [[https://github.blog/2023-04-06-building-github-with-ruby-and-rails | GitHub]], [[https://www.reddit.com/r/rails/comments/z5ricu/how_does_shopify_use_ruby_on_rails/ | Shopify]], etc. * Used in prominent configuration management systems such as [[https://wikiless.tiekoetter.com/wiki/Ansible_(software) | Ansible]], [[https://wikiless.tiekoetter.com/wiki/Chef_(software) | Chef]] and [[https://wikiless.tiekoetter.com/wiki/Puppet_(company)#Puppet | Puppet]]. * Used as a [[https://wikiless.tiekoetter.com/wiki/Domain-specific_language | domain-specific language]] in Chef and Puppet. ---- ===== Ruby Online Resources ===== * http://www.ruby-lang.org - Official site * http://www.ruby-doc.org/ - Official documentation site * http://www.ruby-lang.org/en/documentation/ruby-from-other-languages/ - Coming to Ruby from other languages * https://rubygems.org - The Ruby community’s gem hosting service * Books: * http://ruby-doc.org/docs/ProgrammingRuby/ - "Programming Ruby" * http://www.techotopia.com/index.php/Ruby_Essentials - "Ruby Essentials" * https://github.com/chriskempson/portable-humble-little-ruby-book - "Humble Little Ruby Book" * https://nostarch.com/rubywizardry - "Ruby Wizardry (An Introduction to Programming for Kids)" ===== Ruby Execution ===== * Programs typically given .rb extension * Executed with //ruby prog.rb// * Or use shell script type line at top of Ruby script * #!/path/to/ruby * and make executable with //chmod +x prog.rb// * Interactive shell by running //irb// ---- ===== Ruby: Syntax summary ===== * http://rockhopper.monmouth.edu/~jchung/RubyCheat.pdf (old) * [[https://dev.to/ericchapman/my-beloved-ruby-cheat-sheet-208o|Another cheat sheet]] * A quick reference, in html * http://www.zenspider.com/ruby/quickref.html ===== Ruby: What might be familiar ===== * indentation and whitespace generally not significant * Perl-like //"expression if bool-expr"// and //"expr unless bool-expr"// can be used. * ''print'' and ''puts'' * print omits \n at end * puts includes \n at end ==== Regular expressions ==== * Regular expressions are built-in (like Perl) * Regexp objects can be built with %r|regex| mypattern = %r|[aeiou]| * match with =~ or .match() puts "String has vowels" if "This is a test" =~ /[aeiou]/ puts "String has vowels" if "This is a test".match("[aeiou]") puts "String has vowels" if "This is a test".match( mypattern ) x = "This is a test".match(/(\w+) (\w+)/) puts x[0] puts x[1] puts x[2] * substitute with .sub (1 instance) or .gsub (global sub) puts "foobar".sub('bar', 'foo') puts "this is a test".gsub('i', '') x = "This is a test" puts x.sub(/^../, 'Hello') * Also see the Ruby string class' [[https://ruby-doc.org/core-3.1.1/String.html#method-i-scan|.scan()]] method. * Complete documentation on Ruby regex handling is at https://ruby-doc.org/core-3.1.1/Regexp.html * Includes options for multiline matching and other modifiers. ==== Arrays and hashes ==== * Ruby uses [[http://www.zenspider.com/ruby/quickref.html#arrays|"arrays and hashes"]], like Perl: x = [1, 2, 3, 4] # array called x x << 5 # adds 5 to array x x = { "a" => 1, "b" => 2 } # hash called x # ruby-style iteration through hash: x.each { |key, value| puts "#{key} equals #{value}" } ---- ===== Ruby: What might not be familiar ===== ==== Blocks end with "end" ==== if bool-expr [then] body elsif bool-expr [then] body else body end while bool-expr [do] body end for name[, name]... in expr [do] body end ==== Multi-line strings ==== x = %q{This is a test of the multi line capabilities} ==== Variable interpolation ==== * Use #{varname} or #{expression} x = 10 y = 20 z = "annoying" puts "#{x} + #{y} = #{x + y}" puts "This is so #{z.upcase}!" # also works # puts "This is so " + z.upcase + "!" ==== Ruby-style iteration ==== # Preferred form some_list.each do |this_item| # some statements end # In Python: for this_item in some_list: # In Perl: foreach $this_item (some_list) ==== Ruby naming conventions ==== * Ruby enforces some naming conventions. * If an identifier starts with a capital letter, it is a constant. * Method names, however, are also allowed to start with capital letters. * If it starts with a dollar sign ($), it is a global variable. * such as the built-in **$stdin** global object * See the [[http://rockhopper.monmouth.edu/~jchung/RubyCheat.pdf|cheatsheet]] for other global objects (a.k.a. Predefined Variables). * If it starts with @, it is an instance or object variable. * instance vars have scope within the current object * If it starts with @@, it is a class variable. * like ''static'' variables in Java * class vars have scope within the entire class * Some other conventions * Boolean methods end in ? * Hash#has_key? ( key ) * Methods can be made to mutate their argument(s), by appending ! * Str#downcase! mystring = "Are strings mutable?" mystring.downcase puts mystring + " No." mystring.downcase! puts "#{mystring} It Depends!" ==== Everything except nil and false considered true ==== # in Ruby, 0 is considered true. if 0 puts "0 is true" else puts "0 is false" end ==== Symbols ==== * Symbols, a feature of languages such as LISP * begin with : * don't contain values or objects, unlike variables * can be considered literal constants that have no value current_situation = :good puts "Everything is fine" if current_situation == :good puts "PANIC!" if current_situation == :bad # as opposed to current_situation = "good" puts "Everything is fine" if current_situation == "good" puts "PANIC!" if current_situation == "bad" * Symbols often used in hash creation person1 = { :name => "Fred", :age => 20, :gender => :male } person1 = { :name => "Laura", :age => 23, :gender => :female } ==== Ruby methods (functions) ==== * Methods must be defined before they are called. * The last expression that is evaluated is automatically returned by the method. def say_hello( name ) "Hello, " + name # Same as: return "Hello, " + name end * Method calls typically leave out the parens * Future Ruby versions could require parens, so should retain habit of using parens in method calls. puts say_hello "Chris" # Same as: puts say_hello( "Chris" ) ---- ===== Ruby Classes and Objects ===== ==== Discovering methods ==== * Ruby is sometimes referred to as an "introspective" language. See http://phrogz.net/ProgrammingRuby/ospace.html and https://wikiless.tiekoetter.com/wiki/Type_introspection. * It is possible to query almost any object in Ruby for the methods that are available to it. a = "This is a test" puts a.methods.sort.join(' ') ==== Classes ==== * The Ruby on Rails web app framework necessitates a working knowledge of classes in Ruby. class Person attr_accessor :name, :age, :gender # note use of symbols end person_instance = Person.new person_instance.name = "Robert" person_instance.age = 52 person_instance.gender = "male" puts person_instance.name ==== Intro to class inheritance in Ruby ==== class Pet attr_accessor :name, :age, :gender, :color end class Cat < Pet end class Dog < Pet # Dog-specific method def bark puts "Woof!" end end class Snake < Pet attr_accessor :length # additional attribute for Snake end ==== Using instance or object variables (@varname) ==== # base class Shape class Shape end class Square < Shape # consider initialize method to be the "constructor" def initialize( side_length ) @side_length = side_length end # Instance variables are private by default, so # @side_length is private unless made public with # attr_accessor :side_length # Methods are public unless declared private: def area @side_length * @side_length end def perimeter @side_length * 4 end end class Triangle < Shape def initialize( base_width, height, side1, side2, side3 ) @base_width = base_width @height = height @side1 = side1 @side2 = side2 @side3 = side3 end def area @base_width * @height / 2 end def perimeter @side1 + @side2 + @side3 end end my_square = Square.new( 5 ) my_triangle = Triangle.new( 6, 6, 7.81, 7.81, 7.81 ) puts my_square.area puts my_square.perimeter puts my_triangle.area puts my_triangle.perimeter # Attempt to change @side_length of my_square: my_square.side_length = 10 # will fail without an attr_accessor for :side_length puts my_square.area puts my_square.perimeter * Note the lack of an ''attr_accessor'' for these class definitions. * Without ''attr_accessor'', instance variables are private by default. ==== Using class variables (@@varname) ==== * particularly useful for storing information relevant to all objects of a certain class. * like static class member variables in C++/Java * Example: Store the number of objects created so far in a certain class using a class variable. class Square def initialize if defined?( @@number_of_squares ) @@number_of_squares += 1 else @@number_of_squares = 1 end end # A class method begins with the name of the class itself def Square.count @@number_of_squares # "return" is optional end end a = Square.new puts Square.count b = Square.new puts Square.count ---- ===== Rubygems: Ruby packaging system ===== * RubyGems is a packaging system for Ruby programs and libraries. * Provides //gem// command * Can be thought of as Ruby equivalent of [[cs498gpl:using_the_cpan_module_shell | CPAN]] in Perl and 'pip' in Python. * Try running # List all available gems; hit q to quit the more pager gem list --remote | more # Download and install gems gem install nokogiri open-uri sqlite3 * Each individually packaged Ruby library (or application) is called a //gem// or //RubyGem//. * https://rubygems.org - The Ruby community’s gem hosting service ---- ===== Ruby and databases ===== * Databases and dynamic languages * Perl and Python also have commonly used modules that allow these languages to use SQL databases. * The techniques learned in Ruby are probably applicable to Perl and Python programs that manipulate databases. * Most common use is in web applications that use a database back-end for data storage. * Why databases w/ Ruby? * The Ruby on Rails web app framework is optimized for the creation of database-driven web apps. ==== SQLite with Ruby ==== * SQLite is a lightweight SQL database that does not require a DB server running in the background. * Widely-adopted for configuration management, e.g. Firefox, Chrome and related browsers store user profiles, browsing history, etc. in SQLite databases. * Example: Menu-driven program that allows you to create, manipulate and search a database table. * See [[https://piazza.com/class_profile/get_resource/lrg17jwbqqe603/lumzt8zhtqu4pc|rbdb2.rb]] * After you finish running //rbdb2.rb//, you will have a //dbfile// in the same directory as the Ruby program. ---- ---- ===== Ruby on Rails: An introduction ===== * Ruby on Rails (RoR or Rails) is an open source Web application development framework. * Goal: Make it possible to develop Web applications in an easy, straightforward manner, //with as few lines of code as necessary.// * For this to be possible, Rails makes assumptions and uses default configurations that work for most Web apps. * The attraction of Rails is that it removes much of the groundwork needed to develop Web apps. * Features such as database access, dynamic page elements (AJAX), templating and data validation are either preconfigured or take only a few lines of code to configure. ==== Rails & the Model-View-Controller architecture ==== * Like many contemporary Web app frameworks, Rails uses the [[https://www.codecademy.com/article/mvc|Model-View-Controller]] (MVC) architecture for organizing application programming. * Splits Rails apps into three sections: models, views and controllers * Models * Used to represent forms of data used by the app and contain the logic to manipulate and retrieve that data. * //In Rails, a model is represented as a class.// * Views * The templates and HTML code that users of the Web app see. * Turn data into formats that users can view. * Can output data as HTML for Web browsers, XML, RSS and other formats. * Controllers * Form the logic that binds together models, data and views. * Process input and deliver data for output. * Call methods that are made available by models and deliver it to the views. * Contain methods known as //actions// that generally represent each action relevant to that controller, such as "show," "hide," "view," "delete," and so forth. ==== Ruby on Rails: More Information ==== * Ruby on Rails home: http://www.rubyonrails.org/ * A complete production-level Rails system requires Ruby, the Rails framework (the 'rails' and other Rubygems), a Web server such as Apache or nginx, a database such as MySQL or sqlite, Node.js, and more. * A Rails [[https://guides.rubyonrails.org/getting_started.html#creating-a-new-rails-project-installing-rails|development environment]] requires Ruby, SQLite3, Node.js and Yarn. * I will be working on the CSSE remote [[https://cssegit.monmouth.edu/cshelp/csseremote/-/wikis/MUCSremote|Linux cluster environment]] on which a Rails development environment is already set up. * Install the MUCSremote package for your operating system, and run the linuxlab script to start the remote login process. ==== Sample app - mydiary ==== * See [[cs498gpl/sample_ruby_on_rails_app_-_mydiary]]. ----