diff --git a/.gitignore b/.gitignore
index 1c58a2b..fd50413 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,5 @@
.bundle
*.lock
tryruby/log/*
+tmp/*
+tmp/*
diff --git a/Capfile b/Capfile
new file mode 100644
index 0000000..f8a4084
--- /dev/null
+++ b/Capfile
@@ -0,0 +1,8 @@
+load 'deploy' if respond_to?(:namespace) # cap2 differentiator
+
+# Uncomment if you are using Rails' asset pipeline
+# load 'deploy/assets'
+
+Dir['vendor/gems/*/recipes/*.rb','vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) }
+
+load 'config/deploy' # remove this line to skip loading any of the default tasks
\ No newline at end of file
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..35a352e
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,41 @@
+source 'http://rubygems.org'
+
+gem 'rails', '3.0.9'
+
+gem 'mysql2', '< 0.3'
+gem 'fakefs', '0.2.1', :git => "http://github.com/defunkt/fakefs.git", :ref => "aa0cb96b8ebc81287a2e", :require => 'fakefs/safe'
+# Use unicorn as the web server
+# gem 'unicorn'
+gem 'i18n'
+# Deploy with Capistrano
+# gem 'capistrano'
+
+gem 'devise'
+
+# To use debugger (ruby-debug for Ruby 1.8.7+, ruby-debug19 for Ruby 1.9.2+)
+# gem 'ruby-debug'
+# gem 'ruby-debug19', :require => 'ruby-debug'
+gem 'jquery-rails'
+gem 'ruby_parser'
+gem 'racc'
+
+#gem 'ruby2ruby'
+#gem 'newrelic_rpm'
+#gem 'madmimi'
+#gem 'delayed_job'
+#gem 'dalli'
+# Bundle the extra gems:
+# gem 'bj'
+
+gem 'nokogiri'
+# gem 'sqlite3-ruby', :require => 'sqlite3'
+# gem 'aws-s3', :require => 'aws/s3'
+
+# Bundle gems for the local environment. Make sure to
+# put test-only gems in this group so their generators
+# and rake tasks are available in development mode:
+# group :development, :test do
+ gem 'capybara'
+ gem 'rspec-rails'
+ gem 'cucumber-rails'
+ #gem 'factory-girl'
diff --git a/README b/README
index 1139d90..fe7013d 100644
--- a/README
+++ b/README
@@ -1,97 +1,256 @@
-TRYRUBY! is now 1.9 ready and hosted using 1.9. Please note this is beta software.
+== Welcome to Rails
-Copyright (c) 2009 Andrew McElroy
+Rails is a web-application framework that includes everything needed to create
+database-backed web applications according to the Model-View-Control pattern.
-index.html is Copyright (c) 2009 _why
-test.rb, tryruby_runner.rb Copyright (c) 2009 David Miani
+This pattern splits the view (also called the presentation) into "dumb"
+templates that are primarily responsible for inserting pre-built data in between
+HTML tags. The model contains the "smart" domain objects (such as Account,
+Product, Person, Post) that holds all the business logic and knows how to
+persist themselves to a database. The controller handles the incoming requests
+(such as Save New Account, Update Product, Show Post) by manipulating the model
+and directing data to the view.
+In Rails, the model is handled by what's called an object-relational mapping
+layer entitled Active Record. This layer allows you to present the data from
+database rows as objects and embellish these data objects with business logic
+methods. You can read more about Active Record in
+link:files/vendor/rails/activerecord/README.html.
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without
-restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following
-conditions:
+The controller and view are handled by the Action Pack, which handles both
+layers by its two parts: Action View and Action Controller. These two layers
+are bundled in a single package due to their heavy interdependence. This is
+unlike the relationship between the Active Record and Action Pack that is much
+more separate. Each of these packages can be used independently outside of
+Rails. You can read more about Action Pack in
+link:files/vendor/rails/actionpack/README.html.
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
+== Getting Started
-What is TryRuby?
---------------------------------------------------------------------------------------
-Try Ruby is a interactive shell that quickly and whimsically teaches the Ruby programming language. Originally _why's idea, it has been recreated from the ground up by Rubists who have a passion for Ruby and for teaching their fellow (wo)man how to program.
+1. At the command prompt, create a new Rails application:
+ rails new myapp (where myapp is the application name)
-Please note that If you feel like you are stuck in the middle of a lesson try typing:
+2. Change directory to myapp and start the web server:
+ cd myapp; rails server (run with --help for options)
-next
+3. Go to http://localhost:3000/ and you'll see:
+ "Welcome aboard: You're riding Ruby on Rails!"
-Doing so will skip to to the next part of the less/next lesson
+4. Follow the guidelines to start developing your application. You can find
+the following resources handy:
-UPDATE:
-EXPECT TO SEE THIS CHANGE IN THE NEXT FEW DAYS. I AM LOOKING INTO A SQLITE STORE OPTION.
-The sessions are now stored in a tmp folder.
-For the time being it is within the htdoc path. I know this is bad.
-I have included an index.html that redirects you back to the home page in the mean time.
-Ideally, I need to put this some place like /var/logs/tryruby.
+* The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html
+* Ruby on Rails Tutorial Book: http://www.railstutorial.org/
+== Debugging Rails
-from there I will see about the viability of making this use the r bridge so you
-can have ruby to R lessons. :-)
+Sometimes your application goes wrong. Fortunately there are a lot of tools that
+will help you debug it and get it back on the rails.
-Explaination of /irb.cgi
-========================
-The only part of the TryRuby implementation that wasn't able to be recovered from archive.org is the /irb file (or /irb.cgi currently, you can change the name of the file used in js/irb.js). This script should:
- - Take one GET param "cmd", which will contain a single line of ruby to run. It can also be "!INIT!IRB", which is called at the start of the session. The current implementation of irb.cgi ignores this. "reset" should also do something special (but doesn't atm).
- - Return the output, optionally formatted using normal shell escapes (eg "\033[1;33mThis appears orange")
+First area to check is the application log files. Have "tail -f" commands
+running on the server.log and development.log. Rails will automatically display
+debugging and runtime information to these files. Debugging info will also be
+shown in the browser on requests from 127.0.0.1.
-The output has four main formats for returning a result, error output, javascript function and line continuation. This is used by the help system so that it can detect when a user has entered the next step for the tutorial.
+You can also log your own messages directly into the log file from your code
+using the Ruby logger class from inside your controllers. Example:
-Output results should be formatted with a "=> " at the front of the output. For example: /irb.cgi?cmd=3*4 should output "=> 12". Shell escape codes can be used to give the output different colors, for example "=> \033[1;20m12". This will automatically be removed when used with the help system. Note that you don't and shouldn't terminate these shell escapes with \033[m (like with a normal shell).
+ class WeblogController < ActionController::Base
+ def destroy
+ @weblog = Weblog.find(params[:id])
+ @weblog.destroy
+ logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!")
+ end
+ end
-Standard output should not be prefixed by =>, so /irb.cgi?cmd=puts(44) should output "44\n=> nil". Here 44 is output, and nil is returned. Again shell escapes can be used.
+The result will be a message in your log file along the lines of:
-Errors should be formated just like standard output, however it should have no return. For example, /irb.cgi?cmd=non_existant_function should output something like "\033[1;33mNameError: undefined local variable or method `non_existant_function' for main:Object".
-
-Javascript functions (such as Popup.goto) should use the format "\033[1;JsmJAVASCRIPT CODE\033[m". The javascript cod will then be run. For example, /irb.cgi?cmd=Popup.goto("http://www.google.com") should output \033[1;JSmwindow.irb.options.popup_goto("http://www.google.com")\033[m.
-
-Finally, if the command isn't finished (eg "def myfunc"), then ".." should be returned. Eg /irb.cgi?cmd=def%20myfunc should return "..".
-
-
-How this works with the help system:
-====================================
-The help system works with the file /tutorials/intro.html . There is a
section for each part of the tutorial. Most of it is just the text for that part of the tutorial. However, there is also a
regex
section. If this matches against the output for a command, then the tutorial will go to the next step.
-
-When the class is "answer", then it will match against lines beginning with "=>". So
\d+
will match any code that returns a number. Other output can be shown as well, eg "someoutput\n=> 42" will match this. The exact regexp is '^\s*=> match_regex_from_help\s*$'. So the line must be an exact match, other than spaces and the initial =>
-
-When the class is "stdout", the match must work on a complete line. Eg
hello
will match "hello", or "start\n hello\ngoodbye" (leading spaces are ignored, and multiple lines are searched. The exact regex is '^\s*match_regex_from_help$'
-
-As a special case, if the tutorial expects that a command isn't finished (such as with def myfunc), then it
..
will be used. This is changed from the original implementation _why used, which was as I couldn't get it to work like that.
-
-Another special case, if the return should some javascript code, then something like '
\033\[1;JSm.*popup_goto\(.*\)\033\[m.*
' will be used
-
-
-
-Current Implementation
-======================
-The current implementation doesn't use persistent processes like irb. What it does is it stores all previous successfully run commands in session['previous_commands'], and runs them all first (disabling stdout). Then it will finally run the command. It uses a primitive method of detecting incomplete statements (with the function unfinished_statement?) and when a incomplete statement is finished (finished_statement?). The current nesting level (eg "class X" then "def myfunc" will having a nesting level of 2) is stored in $session['nesting_level']. All the lines of the current incomplete statement are stored in $session['current_statement'].
-
-To work with javascript functions, a special class JavascriptResult was written, with one accessor :js. If the result of an eval returns this object, then the output will be formatted in the javascript method.
+ Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1!
+More information on how to use the logger is at http://www.ruby-doc.org/core/
+Also, Ruby documentation can be found at http://www.ruby-lang.org/. There are
+several books available online as well:
+* Programming Ruby: http://www.ruby-doc.org/docs/ProgrammingRuby/ (Pickaxe)
+* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide)
+These two books will bring you up to speed on the Ruby language and also on
+programming in general.
+== Debugger
+Debugger support is available through the debugger command when you start your
+Mongrel or WEBrick server with --debugger. This means that you can break out of
+execution at any point in the code, investigate and change the model, and then,
+resume execution! You need to install ruby-debug to run the server in debugging
+mode. With gems, use sudo gem install ruby-debug. Example:
+
+ class WeblogController < ActionController::Base
+ def index
+ @posts = Post.find(:all)
+ debugger
+ end
+ end
+
+So the controller will accept the action, run the first line, then present you
+with a IRB prompt in the server window. Here you can do things like:
+
+ >> @posts.inspect
+ => "[#nil, "body"=>nil, "id"=>"1"}>,
+ #"Rails", "body"=>"Only ten..", "id"=>"2"}>]"
+ >> @posts.first.title = "hello from a debugger"
+ => "hello from a debugger"
+
+...and even better, you can examine how your runtime objects actually work:
+
+ >> f = @posts.first
+ => #nil, "body"=>nil, "id"=>"1"}>
+ >> f.
+ Display all 152 possibilities? (y or n)
+
+Finally, when you're ready to resume execution, you can enter "cont".
+
+
+== Console
+
+The console is a Ruby shell, which allows you to interact with your
+application's domain model. Here you'll have all parts of the application
+configured, just like it is when the application is running. You can inspect
+domain models, change values, and save to the database. Starting the script
+without arguments will launch it in the development environment.
+To start the console, run rails console from the application
+directory.
+
+Options:
+
+* Passing the -s, --sandbox argument will rollback any modifications
+ made to the database.
+* Passing an environment name as an argument will load the corresponding
+ environment. Example: rails console production.
+
+To reload your controllers and models after launching the console run
+reload!
+
+More information about irb can be found at:
+link:http://www.rubycentral.com/pickaxe/irb.html
+
+
+== dbconsole
+
+You can go to the command line of your database directly through rails
+dbconsole. You would be connected to the database with the credentials
+defined in database.yml. Starting the script without arguments will connect you
+to the development database. Passing an argument will connect you to a different
+database, like rails dbconsole production. Currently works for MySQL,
+PostgreSQL and SQLite 3.
+
+== Description of Contents
+
+The default directory structure of a generated Ruby on Rails application:
+
+ |-- app
+ | |-- controllers
+ | |-- helpers
+ | |-- mailers
+ | |-- models
+ | `-- views
+ | `-- layouts
+ |-- config
+ | |-- environments
+ | |-- initializers
+ | `-- locales
+ |-- db
+ |-- doc
+ |-- lib
+ | `-- tasks
+ |-- log
+ |-- public
+ | |-- images
+ | |-- javascripts
+ | `-- stylesheets
+ |-- script
+ |-- test
+ | |-- fixtures
+ | |-- functional
+ | |-- integration
+ | |-- performance
+ | `-- unit
+ |-- tmp
+ | |-- cache
+ | |-- pids
+ | |-- sessions
+ | `-- sockets
+ `-- vendor
+ `-- plugins
+
+app
+ Holds all the code that's specific to this particular application.
+
+app/controllers
+ Holds controllers that should be named like weblogs_controller.rb for
+ automated URL mapping. All controllers should descend from
+ ApplicationController which itself descends from ActionController::Base.
+
+app/models
+ Holds models that should be named like post.rb. Models descend from
+ ActiveRecord::Base by default.
+
+app/views
+ Holds the template files for the view that should be named like
+ weblogs/index.html.erb for the WeblogsController#index action. All views use
+ eRuby syntax by default.
+
+app/views/layouts
+ Holds the template files for layouts to be used with views. This models the
+ common header/footer method of wrapping views. In your views, define a layout
+ using the layout :default and create a file named default.html.erb.
+ Inside default.html.erb, call <% yield %> to render the view using this
+ layout.
+
+app/helpers
+ Holds view helpers that should be named like weblogs_helper.rb. These are
+ generated for you automatically when using generators for controllers.
+ Helpers can be used to wrap functionality for your views into methods.
+
+config
+ Configuration files for the Rails environment, the routing map, the database,
+ and other dependencies.
+
+db
+ Contains the database schema in schema.rb. db/migrate contains all the
+ sequence of Migrations for your schema.
+
+doc
+ This directory is where your application documentation will be stored when
+ generated using rake doc:app
+
+lib
+ Application specific libraries. Basically, any kind of custom code that
+ doesn't belong under controllers, models, or helpers. This directory is in
+ the load path.
+
+public
+ The directory available for the web server. Contains subdirectories for
+ images, stylesheets, and javascripts. Also contains the dispatchers and the
+ default HTML files. This should be set as the DOCUMENT_ROOT of your web
+ server.
+
+script
+ Helper scripts for automation and generation.
+
+test
+ Unit and functional tests along with fixtures. When using the rails generate
+ command, template test files will be generated for you and placed in this
+ directory.
+
+vendor
+ External libraries that the application depends on. Also includes the plugins
+ subdirectory. If the app has frozen rails, those gems also go here, under
+ vendor/rails/. This directory is in the load path.
diff --git a/tryruby/Rakefile b/Rakefile
similarity index 57%
rename from tryruby/Rakefile
rename to Rakefile
index 3bb0e85..1e7daf6 100644
--- a/tryruby/Rakefile
+++ b/Rakefile
@@ -1,10 +1,7 @@
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
-require(File.join(File.dirname(__FILE__), 'config', 'boot'))
-
+require File.expand_path('../config/application', __FILE__)
require 'rake'
-require 'rake/testtask'
-require 'rake/rdoctask'
-require 'tasks/rails'
+Tryruby::Application.load_tasks
diff --git a/tryruby/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
similarity index 51%
rename from tryruby/app/controllers/application_controller.rb
rename to app/controllers/application_controller.rb
index 02c13e5..c0bea36 100644
--- a/tryruby/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -1,15 +1,38 @@
# Filters added to this controller apply to all controllers in the application.
# Likewise, all the methods added will be available for all controllers.
+#require File.dirname(__FILE__) + '/../../lib/tryruby'
class ApplicationController < ActionController::Base
+
+
+
+
+ layout 'tryruby'
+
+# attr_accessor :past_commands, :current_statement, :start_time
+
+
+# attr_accessor :past_commands, :current_statement, :start_time
+
+
+
+
+
+=begin
+ #attr_accessor :session
+ TryRuby.session = session
+
+ TryRuby.session['start_time'] ||= Time.now
+ TryRuby.session['current_statement'] ||= ''
+ TryRuby.session['past_commands'] ||= ''
+
helper :all # include all helpers, all the time
protect_from_forgery # See ActionController::RequestForgeryProtection for details
# Scrub sensitive parameters from your log
# filter_parameter_logging :password
#class << self
- attr_accessor :session
- TryRuby.session = TryRuby::Session.new
+=end
# not needed
#end
end
diff --git a/app/controllers/classic_controller.rb b/app/controllers/classic_controller.rb
new file mode 100644
index 0000000..019e234
--- /dev/null
+++ b/app/controllers/classic_controller.rb
@@ -0,0 +1,2 @@
+class ClassicController < ApplicationController
+end
diff --git a/app/controllers/index_controller.rb b/app/controllers/index_controller.rb
new file mode 100644
index 0000000..6a4089a
--- /dev/null
+++ b/app/controllers/index_controller.rb
@@ -0,0 +1,8 @@
+class IndexController < ApplicationController
+ def terminal
+ end
+
+ def index
+
+ end
+end
diff --git a/app/controllers/irb_controller.rb b/app/controllers/irb_controller.rb
new file mode 100644
index 0000000..f296b07
--- /dev/null
+++ b/app/controllers/irb_controller.rb
@@ -0,0 +1,85 @@
+class IrbController < ApplicationController
+ # GET /irb
+ # GET /irb.xml
+ def index
+
+ @irb = []
+
+ respond_to do |format|
+ format.html # index.html.erb
+ format.to_json
+ format.xml { render :xml => @irb }
+ end
+ end
+
+ # GET /irb/1
+ # GET /irb/1.xml
+ def show
+ @irb = Irb.find(params[:id])
+
+ respond_to do |format|
+ format.html # show.html.erb
+ format.xml { render :xml => @irb }
+ end
+ end
+
+ # GET /irb/new
+ # GET /irb/new.xml
+ def new
+ @irb = Irb.new
+
+ respond_to do |format|
+ format.html # new.html.erb
+ format.xml { render :xml => @irb }
+ end
+ end
+
+ # GET /irb/1/edit
+ def edit
+ @irb = Irb.find(params[:id])
+ end
+
+ # POST /irb
+ # POST /irb.xml
+ def create
+ @irb = Irb.new(params[:irb])
+
+ respond_to do |format|
+ if @irb.save
+ format.html { redirect_to(@irb, :notice => 'Irb was successfully created.') }
+ format.xml { render :xml => @irb, :status => :created, :location => @irb }
+ else
+ format.html { render :action => "new" }
+ format.xml { render :xml => @irb.errors, :status => :unprocessable_entity }
+ end
+ end
+ end
+
+ # PUT /irb/1
+ # PUT /irb/1.xml
+ def update
+ @irb = Irb.find(params[:id])
+
+ respond_to do |format|
+ if @irb.update_attributes(params[:irb])
+ format.html { redirect_to(@irb, :notice => 'Irb was successfully updated.') }
+ format.xml { head :ok }
+ else
+ format.html { render :action => "edit" }
+ format.xml { render :xml => @irb.errors, :status => :unprocessable_entity }
+ end
+ end
+ end
+
+ # DELETE /irb/1
+ # DELETE /irb/1.xml
+ def destroy
+ @irb = Irb.find(params[:id])
+ @irb.destroy
+
+ respond_to do |format|
+ format.html { redirect_to(irb_url) }
+ format.xml { head :ok }
+ end
+ end
+end
diff --git a/app/controllers/public_controller.rb b/app/controllers/public_controller.rb
new file mode 100644
index 0000000..2857026
--- /dev/null
+++ b/app/controllers/public_controller.rb
@@ -0,0 +1,2 @@
+class PublicController < ApplicationController
+end
diff --git a/app/controllers/tryruby_controller.rb b/app/controllers/tryruby_controller.rb
new file mode 100644
index 0000000..ec763b7
--- /dev/null
+++ b/app/controllers/tryruby_controller.rb
@@ -0,0 +1,42 @@
+
+class TryrubyController < ApplicationController
+
+ layout 'tryruby'
+ def index
+ end
+
+ def run
+ eval(params[:cmd])
+
+ #@cmd=params[:cmd]
+ # @a= run_script(@cmd)
+ # @b = "handleJSON({\"type\": #{@a.type.to_json}, \"output\":#{@a.output.to_json},\"result\":#{@a.result.inspect.to_json}, \"error\": #{@a.error.inspect.to_json}})"
+
+begin
+ render :json => @b
+ rescue
+ end
+ end
+
+
+ def run_script(command)
+ #output = begin
+ eval(command)
+ # rescue StandardError => e
+ # e.message + ". On the "
+ begin
+ # Tryrubyengine.session ||= TRSession.new
+ #TryRuby.run_line(TryRuby.session.cgi['cmd']).format
+ #Tryrubyengine.new
+ # @c= Tryrubyengine.session
+ # @c.inspect
+ # Tryrubyengine.run_line(command)
+ rescue
+
+ end
+ # end
+
+ # return "=> #{output}" + ", says yoda"
+ end
+
+end
diff --git a/tryruby/app/controllers/tutorials_controller.rb b/app/controllers/tutorials_controller.rb
similarity index 100%
rename from tryruby/app/controllers/tutorials_controller.rb
rename to app/controllers/tutorials_controller.rb
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
new file mode 100644
index 0000000..d995b05
--- /dev/null
+++ b/app/helpers/application_helper.rb
@@ -0,0 +1,18 @@
+module ApplicationHelper
+
+ def google_analytics_js
+ ua_code = "UA-2365371-3"
+ ''
+
+ end
+
+end
diff --git a/app/helpers/classic_helper.rb b/app/helpers/classic_helper.rb
new file mode 100644
index 0000000..e85110a
--- /dev/null
+++ b/app/helpers/classic_helper.rb
@@ -0,0 +1,2 @@
+module ClassicHelper
+end
diff --git a/app/helpers/index_helper.rb b/app/helpers/index_helper.rb
new file mode 100644
index 0000000..cdc64c7
--- /dev/null
+++ b/app/helpers/index_helper.rb
@@ -0,0 +1,2 @@
+module IndexHelper
+end
diff --git a/app/helpers/irb_helper.rb b/app/helpers/irb_helper.rb
new file mode 100644
index 0000000..6c9f3c9
--- /dev/null
+++ b/app/helpers/irb_helper.rb
@@ -0,0 +1,2 @@
+module IrbHelper
+end
diff --git a/app/helpers/public_helper.rb b/app/helpers/public_helper.rb
new file mode 100644
index 0000000..0d8e188
--- /dev/null
+++ b/app/helpers/public_helper.rb
@@ -0,0 +1,2 @@
+module PublicHelper
+end
diff --git a/app/helpers/tutorials_helper.rb b/app/helpers/tutorials_helper.rb
new file mode 100644
index 0000000..30716fd
--- /dev/null
+++ b/app/helpers/tutorials_helper.rb
@@ -0,0 +1,2 @@
+module TutorialsHelper
+end
diff --git a/tryruby/log/production.log b/app/views/index/index.html.erb
similarity index 100%
rename from tryruby/log/production.log
rename to app/views/index/index.html.erb
diff --git a/tryruby/log/server.log b/app/views/index/terminal.html.erb
similarity index 100%
rename from tryruby/log/server.log
rename to app/views/index/terminal.html.erb
diff --git a/app/views/irb/_form.html.erb b/app/views/irb/_form.html.erb
new file mode 100644
index 0000000..4e3cdae
--- /dev/null
+++ b/app/views/irb/_form.html.erb
@@ -0,0 +1,17 @@
+<%= form_for(@irb) do |f| %>
+ <% if @irb.errors.any? %>
+
+
<%= pluralize(@irb.errors.count, "error") %> prohibited this irb from being saved:
+
+
+ <% @irb.errors.full_messages.each do |msg| %>
+
<%= msg %>
+ <% end %>
+
+
+ <% end %>
+
+
+ <%= f.submit %>
+
+<% end %>
diff --git a/app/views/irb/edit.html.erb b/app/views/irb/edit.html.erb
new file mode 100644
index 0000000..9e50dc3
--- /dev/null
+++ b/app/views/irb/edit.html.erb
@@ -0,0 +1,6 @@
+
First, I'd like to thank the over 365,345 (three hundred sixty five thousand three hundred fourty five) people who have used Try Ruby (globally) over 508,600 (five hundred eight thousand six hundred) times in the last two years!
+
It has been an honor and a privlege to help restore such a fantastic resource.
+
Because of the fun nature of Try Ruby, it only makes sense to allow it to reach its full potential.
+
Specifically, Try Ruby must have lessons for the full language.
+
A partial list includes
+
+
Blocks, Lambdas, Closures, and Procs
+
Object Model (DrX with a live svg front end)
+
Metaprogramming
+
Sandboxing
+
Standard lib
+
Unit Testing & Outside in Behavior Driven Development
+
The Ruby VM (Garbage Collection, Tuning, etc)
+
Try Ruby Offline & Mobile versions.
+
+
+
I have gladly covered the hosting expense (currently amazon ec2 small instance, and before that a dedicated box) for the last two years.
+ The smile people have when experiencing the beauty of Ruby has been more than worth it. :-)
+
However, in order allow Try Ruby's potential to flourish- muchless stay online- I am currently raising funds. I have never placed ads or sold any information collected by Try Ruby. Please donate to help this site reach its full potential.
+
If all goes well, I will have weekly lessons, much in the spirit of Railscasts. Obviously these would be interative lessons.
+
Last, I'd like to thank David Miani for helping me reassemble Try Ruby when _why disappeared*. Also, a thanks goes out to Adrian aka "Orangea" for his eairly work in finding security holes and helping with other misc issues. A deep thanks also goes out to everyone who has ever reported a bug or issue with Try Ruby.
+
Thank You.
+ Respectfully,
+ Andrew McElroy
+
* _why the lucky stiff was the origional creator of Try Ruby. However he vanished from the Internet over two years ago. He took his copy of Try Ruby with him. We had to completely reimplement Try Ruby.
Ruby is a programming language from Japan
+ (available at ruby-lang.org)
+ which is revolutionizing the web.
+ The beauty of Ruby is found in its balance between simplicity and power.
+
+
Try out Ruby code in the prompt above. In addition
+ to Ruby's builtin methods, the following commands are available:
+
+
help
+ Start the 15 minute interactive tutorial. Trust me, it's very basic!
+
help 2
+ Hop to chapter two.
+
+
clear
+ Clear screen. Useful if your browser starts slowing down.
+ Your command history will be remembered.
+
back
+ Go back one screen in the tutorial.
+
reset
+ Reset the interpreter if you get too deep. (or Ctrl-D!)
+
next
+Allows you to skip to the next section of a lesson.
+
+
time
+ A stopwatch. Prints the time your session has been open.
+
+
If you happen to leave or refresh the page, your session will still be here for
+ unless it is left inactive for ten minutes.
+
+
+
+
+
+
Trapped in double dots? A quote or something was left open. Type: reset or hit Ctrl-D.
+
+
+
This place was sired by why the lucky stiff.
+ Please contact me using the email address at that link.is maintained by Andrew McElroy and David Miani. For support issues, please post a ticket or contact Sophrinix on github.
+
+
+
+
+
+
+
+
+
+
+
+Please Support Try Ruby!
+
+
+
diff --git a/tryruby/public/favicon.ico b/app/views/layouts/blank.html.erb
similarity index 100%
rename from tryruby/public/favicon.ico
rename to app/views/layouts/blank.html.erb
diff --git a/tryruby/app/views/layouts/tryruby.rhtml b/app/views/layouts/tryruby.rhtml
similarity index 52%
rename from tryruby/app/views/layouts/tryruby.rhtml
rename to app/views/layouts/tryruby.rhtml
index 7d7fadc..9ab71c1 100644
--- a/tryruby/app/views/layouts/tryruby.rhtml
+++ b/app/views/layouts/tryruby.rhtml
@@ -2,90 +2,85 @@
-
- try ruby! (in your browser)
+ try ruby! (en tu navegador)
-
-
-
+
-
+
Ruby is a programming language from Japan
- (available at ruby-lang.org)
- which is revolutionizing the web.
- The beauty of Ruby is found in its balance between simplicity and power.
-
-
Try out Ruby code in the prompt above. In addition
- to Ruby's builtin methods, the following commands are available:
+
¿Tienes 15 minutos? ¡Prueba Ruby ahora mismo!
+
Ruby es un lenguaje de programación de Japón
+ (disponible en ruby-lang.org)
+ que está revolucionando la web.
+ La belleza de Ruby se encuentra en su balance entre la simplicidad y el poder.
+
+
Prueba código Ruby en el prompt de arriba. Además de los métodos
+ originales de Ruby, los siguientes comandos están disponibles:
help
- Start the 15 minute interactive tutorial. Trust me, it's very basic!
+ Empieza el tutorial interactivo de 15 minutos. ¡Creeme, es muy básico!
help 2
- Hop to chapter two.
-
+ Salta al capítulo 2.
+
clear
- Clear screen. Useful if your browser starts slowing down.
- Your command history will be remembered.
+ Limpia la pantalla. Útil si tu navegador empieza a alerdarce.
+ Tu historial de comandos será recordado.
back
- Go back one screen in the tutorial.
+ Retrocede una pantalla en el tutorial.
reset
- Reset the interpreter if you get too deep. (or Ctrl-D!)
-
next
-Allows you to skip to the next section of a lesson.
-
+ Resetea el interprete. (o Ctrl-D!)
+
next
+ Te permite saltear la siguiente lección
+
time
- A stopwatch. Prints the time your session has been open.
+ Detiene el reloj. Imprime cuanto tiempo tu sesión estuvo abierta.
-
If you happen to leave or refresh the page, your session will still be here for
- unless it is left inactive for ten minutes.
+
Si te pasa de dejar o refrescar la página, tu sesión seguirá aquí a menos que
+ se deje inactiva por diez minutos.
-
+
-
Trapped in double dots? A quote or something was left open. Type: reset or hit Ctrl-D.
+
¿Atrapado en los dos puntos? Unas comillas o algo fue dejado abierto. Escribe: reset o aprieta Ctrl-D.
-
This place is maintained by Andrew McElroy and David Miani and Orangea. For support issues, please post a ticket or contact Sophrinix on github.
+
This place was sired by why the lucky stiff.
+ Please contact me using the email address at that link.is maintained by Andrew McElroy and David Miani. For support issues, please post a ticket or contact Sophrinix on github. Por asuntos de traducción, mandar un ticket o contactarse con Cristian Re (leizzer) en Github.
-
+
-
-
+
-
+
diff --git a/tryruby/app/views/layouts/tryruby2.html.erb b/app/views/layouts/tryruby_2.html.erb
similarity index 100%
rename from tryruby/app/views/layouts/tryruby2.html.erb
rename to app/views/layouts/tryruby_2.html.erb
diff --git a/app/views/tryruby/_donate.html.erb b/app/views/tryruby/_donate.html.erb
new file mode 100644
index 0000000..f7095b1
--- /dev/null
+++ b/app/views/tryruby/_donate.html.erb
@@ -0,0 +1,41 @@
+
+
Please Support Try Ruby!
+
+
+
+
+
+
+
+
First, I'd like to thank the over 365,345 (three hundred sixty five thousand three hundred fourty five) people who have used Try Ruby (globally) over 508,600 (five hundred eight thousand six hundred) times in the last two years!
+
It has been an honor and a privlege to help restore such a fantastic resource.
+
Because of the fun nature of Try Ruby, it only makes sense to allow it to reach its full potential.
+
Specifically, Try Ruby must have lessons for the full language.
+
A partial list includes
+
+
Blocks, Lambdas, Closures, and Procs
+
Object Model (DrX with a live svg front end)
+
Metaprogramming
+
Sandboxing
+
Standard lib
+
Unit Testing & Outside in Behavior Driven Development
+
The Ruby VM (Garbage Collection, Tuning, etc)
+
Try Ruby Offline & Mobile versions.
+
+
+
I have gladly covered the hosting expense (currently amazon ec2 small instance, and before that a dedicated box) for the last two years.
+ The smile people have when experiencing the beauty of Ruby has been more than worth it. :-)
+
However, in order allow Try Ruby's potential to flourish- muchless stay online- I am currently raising funds. I have never placed ads or sold any information collected by Try Ruby. Please donate to help this site reach its full potential.
+
If all goes well, I will have weekly lessons, much in the spirit of Railscasts. Obviously these would be interative lessons.
+
Last, I'd like to thank David Miani for helping me reassemble Try Ruby when _why disappeared*. Also, a thanks goes out to Adrian aka "Orangea" for his eairly work in finding security holes and helping with other misc issues. A deep thanks also goes out to everyone who has ever reported a bug or issue with Try Ruby.
+
Thank You.
+ Respectfully,
+ Andrew McElroy
+
* _why the lucky stiff was the origional creator of Try Ruby. However he vanished from the Internet over two years ago. He took his copy of Try Ruby with him. We had to completely reimplement Try Ruby.
+
\ No newline at end of file
diff --git a/app/views/tryruby/index.html.erb b/app/views/tryruby/index.html.erb
new file mode 100644
index 0000000..e69de29
diff --git a/app/views/tryruby/run.html.erb b/app/views/tryruby/run.html.erb
new file mode 100644
index 0000000..e69de29
diff --git a/tryruby/app/views/tutorials/es_intro.html b/app/views/tutorials/es_intro.html
similarity index 100%
rename from tryruby/app/views/tutorials/es_intro.html
rename to app/views/tutorials/es_intro.html
diff --git a/app/views/tutorials/intro.html.erb b/app/views/tutorials/intro.html.erb
new file mode 100644
index 0000000..56c1d1c
--- /dev/null
+++ b/app/views/tutorials/intro.html.erb
@@ -0,0 +1,680 @@
+
+
+
Using the Prompt
+
The blue window above is a Ruby prompt. Type a line of Ruby code, hit Enter
+ and watch it run!
+
For example, try typing some math. Like: 2 + 6
+
\d+
+
+
+
Numbers & Math
+
Good! You did a bit of math. See how the answer popped out?
+
Ruby recognizes numbers and mathematic symbols. You could try some other math like:
+
4 * 10
+
5 - 12
+
40 / 4
+
Sure, computers are handy and fast for math. Let's move on. Want to see your name reversed?
+ Type your first name in quotes like this: "Jimmy"
+
"(\w+)"
+
+
+
Say Your Name Backwards
+
Perfect, you've formed a string from the letters of your name. A string
+ is a set of characters the computer can process.
+
Imagine the letters are on a string of
+ laundry line and the quotes are clothespins holding the ends. The quotes mark the beginning and end.
+
To reverse your name, type: "Jimmy".reverse (Don't forget the dot!)
+
"(\w+)"
+
+
+
Counting the Letters
+
You have used the reversemethod on your name! By enclosing your name in
+ quotes, you made a string. Then you called the reverse method, which works on strings to flip
+ all the letters backwards.
+
Now, let's see how many letters are in your name: "Jimmy".length
+
\d+
+
+
+
On Repeat
+
Now, I'm sure by now you're wondering what any of this is good for. Well, I'm sure you've been to
+ a website that screamed, Hey, your password is too short! See, some programs
+ use this simple code.
+
Watch this. Let's multiply your name by 5. "Jimmy" * 5
+
"(\w+)"
+
+
+
Hey, Summary #1 Already
+
Let's look at what you've learned in the first minute.
+
+
The prompt. Typing code into the green prompt gives you
+ an answer from a red prompt. All code gives an answer.
+
Numbers and strings are Ruby's math and text objects.
+
Methods. You've used English-language methods like reverse
+ and symbolic methods like * (the multiplication method.) Methods are action!
+
+
This is the essence of your learning. Taking simple things, toying with
+ them and turning them into new things. Feeling comfortable yet? I promise you are.
+
Okay, let's do something uncomfortable. Try reversing a number: 40.reverse
+
NoMethodError: undefined method `reverse' for (\d+):Fixnum
+
+
+
Stop, You're Barking Mad!
+
You can't reverse the number forty. I guess you can hold your monitor up to the
+ mirror, but reversing a number just doesn't make sense. Ruby has tossed an error
+ message. Ruby is telling you there is no method reverse for numbers.
+
Maybe if you turn it into a string: 40.to_s.reverse.
+
\"(\d+)\"
+
+
+
Boys are Different From Girls
+
And numbers are different from strings. While you can use methods on any object
+ in Ruby, some methods only work on certain types of things. But you can always
+ convert between different types using Ruby's "to" methods.
+
to_s converts things to strings.
+
to_i converts things to integers (numbers.)
+
to_a converts things to arrays.
+
+
What are arrays?! They are lists. Type in a pair of brackets: [].
+
\[\]
+
+
+
Standing in Line
+
Great, that's an empty list. Lists store things in order.
+ Like standing in line for popcorn. You are behind someone and you wouldn't
+ dream of pushing them aside, right? And the guy behind you, you've got a
+ close eye on him, right?
+
Here's a list for you. Lottery numbers: [12, 47, 35].
+
\[(\d+(, )?){2,}\]
+
+
+
One Raises Its Hand
+
A list of lottery numbers. Which one is the highest?
+
Try: [12, 47, 35].max.
+
(\d+)
+
+
+
Tucking a List Away
+
Good, good. But it's annoying to have to retype that list, isn't it?
+
Let's save our numbers inside a ticket like so: ticket = [12, 47, 35]
+
\[(\d+(, )?){2,}\]
+
+
+
Now Type Ticket
+
Now, type: ticket
+
\[(\d+(, )?){2,}\]
+
+
+
Saved, Tucked Away
+
Fantastic! You've hung on to your lotto numbers, tucking them away inside a
+ variable called ticket.
+
Let's put your lotto numbers in order, how about? Use: ticket.sort!
+
\[(\d+(, )?){2,}\]
+
+
+
Summary #2 is Upon Us
+
You had a list. You sorted the list. The ticket variable is now changed.
+
Did you notice that the sort! method has a big, bright exclamation at the end?
+ A lot of times Ruby methods shout like that if they alter the variable for good. It's nothin
+ special, just a mark.
+
Now, look how your second minute went:
+
+
Errors. If you try to reverse a number or do anything fishy,
+ Ruby will skip the prompt and tell you so.
+
Arrays are lists for storing things in order.
+
Variables save a thing and give it a name. You used the
+ equals sign to do this. Like: ticket = [14, 37, 18].
+
+
In all there are eight lessons. You are two-eighths of the way there!
+ This is simple stuff, don't you think? Good stuff up ahead.
+
Let's change directions for a moment. I've stuffed a bit of poetry for you in
+ a certain variable. Take a look. Type print poem
+
poem = "My toast has flown from my hand\nAnd my toast has gone to the
+moon.\nBut when I saw it on television,\nPlanting our flag on Halley's
+comet,\nMore still did I want to eat it.\n"
+
My toast (.+)
+
+
+
Sadly, You Hate Toast Poetry
+
Look, it's okay. You don't have to like it. Hack it up, be my guest.
+
Instead of toast, go for a melon or something. Try this: poem['toast'] = 'honeydew'
+
And then type print poem by itself to see the new poem.
+
My honey(.+)
+
+
+
Ready, Aim
+
The square brackets you just used are very common in Ruby. Remember, you typed: poem['toast'] = 'honeydew'. That box with the word toast has a square bracket on each side, see?
+
The
+two brackets are like sights used to line up a target. Exactly. These
+brackets mean, "I am looking for ____." Ready, aim. Here you're looking
+for toast and swapping it out with fruit.
+
Here's a question: what happens when we reverse this whole poem? poem.reverse
+
"\\n.ti tae ot (.+)"
+
+
+
Too Much Reversal
+
Okay, sure. So the whole poem's been turned backwards, letter-by-letter. I really want to just
+ reverse the lines, though. Move the last line up to first and the first line down to last. Backwards, but not
+ that backwards.
+
Here's how: poem.lines.to_a.reverse
+
\["More still did I(.+)"\]
+
+
+
Ringlets of Chained Methods
+
So what do you see? What happened there? You typed poem.lines.to_a.reverse and what happened?
+
Two things happened. You turned the poem into a
+list using lines.to_a. lines decides the way
+the string is split up, then to_a converted it into an
+Array. (To array.) Different methods, such
+as bytes and chars can be used in place
+of lines. By using lines, ruby will return each line of the poem.
+
Then, you reversed that list. You had each line. You reversed them. That's it.
+
Let's tack one more method on the end there: print poem.lines.to_a.reverse.join
+
More still did I(.+)
+
+
+
Of All the Summaries, #3 is Here Now
+
Good show, my friend! The join method took that list of reversed lines and put them
+ together into a string. (Sure, you could have also just used to_s.)
+
Review time.
+
+
Exclamations. Methods may have exclamations (and also question marks)
+ in their name. No big deal. Try: poem.include? "my hand"
+
Square brackets. Target and find things. Search and replace.
+
Chaining methods lets you get a lot more done. Break up a poem,
+ reverse it, reassemble it: poem.lines.to_a.reverse.join
+
+
At this point, you may want to tinker with the poem a bit more. A complete list of all
+ the String methods is
+
+ here.
+ Go ahead and try a few (such as poem.downcase or poem.delete.)
+
When you're ready to move on, type: books = {}
+
\{\}
+
+
+
A Wee Blank Book
+
You've made an empty hash. (Also known as: an empty dictionary.)
+
We're going to stuff some miniature book reviews in this hash. Here's our rating system:
+
+
:splendid → a masterpiece.
+
:quite_good → enjoyed, sure, yes.
+
:mediocre → equal parts great and terrible.
+
:quite_not_good → notably bad.
+
:abyssmal → steaming wreck.
+
+
To rate a book, put the title in square brackets and put the rating after the equals.
+
For example: books["Gravity's Rainbow"] = :splendid
+
:\w+
+
+
+
More Bite-Size Reviews
+
Keep going, fill it up with reviews. And, if you want to see the whole list,
+ just type: books
+
Again, the ratings are: :splendid, :quite_good, :mediocre,
+ :quite_not_good, and :abyssmal.
+
These ratings are not strings. When you place a colon in front of a simple word, you get a
+ symbol. Symbols are cheaper than strings (in terms of computer memory.) If
+ you use a word over and over in your program, use a symbol. Rather than having thousands of
+ copies of that word in memory, the computer will store the symbol only once.
+
Once you've got three or four books in
+ there, type: books.length.
+
[3-9]
+
+
+
Wait, Did I Like Gravity's Rainbow?
+
See, the length method works on strings, list and hashes. One great thing about
+ Ruby is that names are often reused, which means fewer names you need to remember.
+
If you'd like to look up one of your old reviews, again put the title in the square. But leave off
+ the equals.
+
Just like this: books["Gravity's Rainbow"]
+
:\w+
+
+
+
Hashes as Pairs
+
Keep in mind that hashes won't keep things in order. That's not their job. It'll just pair up two
+ things: a key and a value. In your reviews, the key is the book's
+ title and the value is the rating.
+
If you want to just see the titles of the books you've reviewed: books.keys
+
\[".*"\]
+
+
+
Are You Harsh?
+
So are you giving out harsh, unfair reviews? Let's keep score with this hash: ratings = Hash.new {0}
+
Then, okay, now let's count up your reviews. Just stay with me. Type:
+ books.values.each { |rate| ratings[rate] += 1 }
+
(The straight line in the code is the pipe character, probably located right above the
+ Enter key on your keyboard.)
+
\[:.+\]
+
+
+
A Tally
+
Great, wow! You've made a scorecard of your ratings. Type ratings to see the count.
+ This new hash shows a rating and then the number of times you've given that rating.
+
One of the amazing new things we've just used is a block. We're going to
+ explore these more in the next summary. But, basically, a block is a bit of Ruby code surrounded
+ by curly braces.
+
Let's try another block: 5.times { print "Odelay!" }
+
Odelay!Od.*
+
+
+
Now Arriving at Summary #4
+
Blocks are always attached to methods. Like the times method, which takes the
+ block and runs the code over and over. (In this case: five times.)
+
This last lesson was a bit longer. You've probably used up three minutes learning about:
+
+
Hashes. The little dictionary with the curly pages: {}.
+
Symbols. Tiny, efficient code words with a colon: :splendid.
+
Blocks. Chunks of code which can be tacked on to many of Ruby's methods. Here's the
+ code you used to build a scorecard: books.values.each { |rate| ratings[rate] += 1 }.
+
+
On your computer, you probably have a lot of different files. Files with pictures in them,
+ files with programs in them. And files are often organized into folders, also called:
+ directories.
+
I've prepared a few directories for you. Take a look:
+ Dir.entries "/"
+
\["\.", .+\]
+
+
+
The Private Collection of Dr. Dir
+
You've just listed out everything in the top directory. The root directory, indicated
+ by a single slash. Containing some programs and other tutorials and such.
+
So, what is the Dir.entries method? Well, it's just a method, right?
+ entries is a method called on the Dir variable.
+ And Dir has a collection of methods for checking out file directories.
+
One other little thing we haven't really talked about openly. Method arguments, highlighted in green.
+
+
Dir.entries "/": Anything listed after a method
+ is considered an attachment.
+
print poem: See, print is an ordinary method. And the
+ poem is attached. To be printed.
+
print "pre", "event", "ual", "ism" has several arguments, with commas
+ between them.
+
+
To list just the text files in that directory: Dir["/*.txt"]
+
\["\/comics\.txt"\]
+
+
+
Come, Read Comics With Me
+
The Dir[] method is like entries but you search for files
+ with wildcard characters. Here, we see those square brackets again! Notice how
+ they still mean, "I am looking for _____?"
+
More specifically: "I am looking for files which end with .txt."
+
Let's crack open this comics file, then. Here's the way:
+ print File.read("/comics.txt")
+
Achewood.+
+
+
+
Mi Comicas, Tu Comicas
+
All right! We can start to use files to store things. This is great because normally when
+ we exit Ruby, all our variables will be gone. Ruby, by itself, forgets these things.
+ But if we save things in files, we can read those files in future Ruby escapades.
+
Hey, and guess what? The /Home directory is yours! I gave it to you! I am generous! Let's make a copy of the comics file.
+
You'll want to: FileUtils.copy('/comics.txt', '/Home/comics.txt')
+
If you've already created the file, use File.delete('/Home/comics.txt') to trash it.
+
nil
+
+
+
Your Own Turf
+
Okay, you've got a copy. Check it: Dir["/Home/*.txt"]
+
To add your own comic to the list, let's open the file in append mode.
+
Start like this: File.open("/Home/comics.txt", "a") do |f|.
+
..
+
+
+
And Now For the Startling Conclusion
+
So your prompt has changed. See that? Your prompt is a double dot now.
+
In this tutorial, this prompt means that Ruby is expecting you to type more.
+ As you type in the lines of Ruby code, the double dots will continue until you
+ are completely finished.
+
Hot tip: If you want to stop working on the code and break out of the double dots, use the reset
+ command. If you want to go the previous page of the tutorial, use the back command.
+
Here's your code. You've already typed the first line, so just enter the second line. (The \n
+ is an Enter character.
+
File.open("/Home/comics.txt", "a") do |f|
+
f << "Cat and Girl: http://catandgirl.com/\n"
+
end
+
+
And, since you're getting so advanced and capable here, one other tip: you can use the up and down arrow keys to
+ edit your old commands or run them again.
+
..
+
+
+
Ruby Sits Still
+
That last line adds the Cat and Girl comic to the list, but Ruby's going to wait until you're totally finished to
+ take action.
+
Now, to finish the code you've started. You opened a new block when you typed do.
+ So far the blocks we've seen have used curly braces. This time we'll be using do and end instead
+ of curly braces. A lot of Rubyists will use do...end when the block goes on for many lines.
+
Let's get that block finished now, with: end
+
File.open("/Home/comics.txt", "a") do |f|
+
f << "Cat and Girl: http://catandgirl.com/\n"
+
end
+
+
#.File:/Home/comics\.txt \(closed\).
+
+
+
The Clock Nailed To the File
+
Good, good! You've added that new comic to the file. You can see for yourself: print File.read("/Home/comics.txt")
+
What time was it when you changed the file? Let's check. Type: File.mtime("/Home/comics.txt")
+
\d{4}-\d+-\d+ \d{2}:\d{2}:\d{2} [+-]\d{4}
+
+
+
Just the Hour Hand
+
Great, there's the time. The precise time exactly when you added to the file. The mtime gives you a Ruby Time object.
+
If you want to check just what hour it was, hit the up arrow key and change the line to: File.mtime("/Home/comics.txt").hour
+
\d+
+
+
+
Hallo, Who's There? And Summary #5 Waves Its Hat!
+
Well done, well done, well done, well done! Truly, truly, truly, truly, truuuuuuuuly!
+
Here's the last few minutes of your life in review:
+
+
Files. What more can be said? Lots of methods for editing files and lookin around in directories.
+
Arguments. Arguments are a list of things sent into a method. With commas between.
+
We also spoke about do and end which are another way to make a block.
+
+
You totally know how to use Ruby now. I mean you've got down the essentials. You just need to keep learning more methods and
+ try out more complex blocks.
+
But there's one side of Ruby we haven't settled. Making your own methods and classes.
+
Ahem! Let's get it over with then.
+
Start with: def load_comics( path )
+
..
+
+
+
In Ruby, Def Leppard Means Define Leppard (a Method)!
+
Hey, okay, you done it. You're making your own method. You started with def, followed by the name of the method.
+ And a list of arguments which the method will need. This isn't too scary and dangerous!
+
All we have to do is fill it up with Ruby and finish it up with end.
+
Here's the code:
+
def load_comics( path )
+
comics = {}
+
File.foreach(path) do |line|
+
name, url = line.split(': ')
+
comics[name] = url.strip
+
end
+
comics
+
end
+
+
No need to indent, if you don't want. I just do that to make it read easier.
+
nil
+
+
+
The Ripened Fruit of Your Own Creation
+
A new method is born. Let us use it: comics = load_comics('/comics.txt')
+
If you have a problem, you might have mistyped. Use the back command and try again.
+
\{.*"Achewood"=."http://achewood.com/".*\}
+
+
+
Hey, Cool, a Comics Thing
+
In your Ruby window above, look at the code you've typed for the load_comics method. What is happening? You're
+ passing in the path variable and you're getting back the comics variable. Ruby lets the comics
+ hash trickle out the end of the method.
+
A number of methods were used to get the job done. See if you can spot them.
+
File.foreach is a method which opens a file and hands each line to the block. The line
+ variable inside the do...end block took turns with each line in the file.
+
split is a method for strings, which breaks the string up into an array. An axe is laid on the colon
+ and the line is chopped in half, giving us the url and name for each comic.
+
strip removes extra spaces around the name. Just in case.
+
+
Right on. Bravo. You've got the comics in a Ruby hash. But what now? What good is this really?
+
Let's make a page of links. How about that? I went ahead and loaded a little library I've made for you.
+
Type: next. This is temporary as I updates new lessons.
+
true
+
+
+
Browser Puppetry
+
Excellent, you've loaded the popup library. It's saved in a file in the Libraries folder. See: Dir["/Libraries/*"]
+
The popup library contains a bunch of methods I've written which let you control a popup here on the Try Ruby site.
+
Here, try this: Popup.goto "http://google.com/"
+
\033\[1;JSm.*popup_goto\(.*\)\033\[m.*
+
+
+
Making Links and Spinning Webs
+
Our own lovely, little popup to manipulate. You can also fill it with your own goodies. We'll start small:
+
Popup.make {
+
h1 "My Links"
+
link "Go to Google", "http://google.com/"
+
}
+
+
The term h1 (h-one) means a level-one header. In HTML, this is the largest size of header.
Okay, this is coming along wonderfully. This is simple stuff, but keep in mind that you didn't know any Ruby whatsoever just fifteen minutes ago!
+
Last
+step. Let's tie it all together, you know? Let's make it chime together
+like a very nice set of glistening chimes on the beach in the
+maginificent sunlight!
+
Make sure the comics are loaded: comics = load_comics( '/comics.txt' )
+
Now, let's make a list of the links to each comic:
+
Popup.make do
+
h1 "Comics on the Web"
+
list do
+
comics.each do |name, url|
+
link name, url
+
end
+
end
+
end
+
+
You can click on the links and read the comics in the little window even! Smashing!
You're a level six Ruby cleric. I mean what a great job you've done. Let's review:
+
+
You added your own method with def and you used that load_comics method several times.
+
Libraries. You used the require method to load the popup library. By typing: require 'popup'
+
And if that wasn't enough, you made your own web page from a list of comics in a file. You made a real program!
+
+
So
+what could possibly be next? What could you possibly have to learn now?
+Ha, this is the best part. You've come such a long way that we're going
+to uncover classes. For two more short lessons and you're done.
+
Earlier, we created a hash like this: Hash.new Try it.
+
\{\}
+
+
+
Not a School Class, a Working Class
+
You see, the empty curly braces {} is a shortcut for Hash.new. The new
+method is used to make objects of a certain class. (Think "class" as in
+"working class" — a specific group of objects which are similar, have
+the same jobs, the same shirts.)
+
Ask yourself this: How would I make a blog in Ruby?
+Where would you start? Well, you might store your blog entries in a
+file, right? But how would you keep track of the title of the entry and
+the time it was posted? And when you loaded the file, how would it look
+in Ruby? Would it be a Hash? Or an Array? Or an Array of Arrays? Or
+something else?
I really think you'll want to use a class. You are already familiar with many classes: Hash, Array, String.
+
Let's make a new class: class BlogEntry.
+
..
+
+
+
The Stuff Blogs are Made of
+
You've opened up a new BlogEntry class. What is your blog entry made of? A title, sure. Also, a time when the entry was posted. The
+ full text of the entry.
+
We'll do a mood setting, too, just like LiveJournal. The Internet has really brought back stick people and smileys
+ out of bankruptcy. Emote!
+
Okay, so you've got the first line of the class, here's the rest:
+
class BlogEntry
+
attr_accessor :title, :time, :fulltext, :mood
+
end
+
+
nil
+
+
+
Accessors Are the Dangling Limbs
+
Hey, good class, man. You've got a new BlogEntry class. To start an entry: entry = BlogEntry.new.
+
In the class definition, you used a method called attr_accessor. There are many attribute methods like
+ this which add little settings to classes. These attributes are just variables attached to a class.
+
Think
+of it this way. A class is like a person. That star-shaped human thing
+out there. And the attributes are the dangling limbs, the different
+parts that make up a body.
+
To set the title of your entry: entry.title = "Today Mt. Hood Was Stolen!"
+
".+"
+
+
+
An Object, That Neat Little Package
+
Go ahead and set the post time: entry.time = Time.now
+
And the mood: entry.mood = :sick
+
And the post itself: entry.fulltext = "I can't believe Mt. Hood was stolen! I am speechless! It was stolen by a giraffe who drove away
+ in his Cadillac Seville very nonchalant!!"
+
To see all your settings, just type at the prompt: entry.
Cool,
+you're blog is awesome. Hey, let's make things a bit easier on you.
+You're not going to want to set the time like that every time you post.
+You just want to type in the title and the entry and the mood quickly,
+right?
+
Let's add an initialize method.
+
class BlogEntry
+
def initialize( title, mood, fulltext )
+
@time = Time.now
+
@title, @mood, @fulltext = title, mood, fulltext
+
end
+
end
+
+
Once you've got that typed in, try making a new entry: BlogEntry.new
+
ArgumentError: wrong number of arguments \(0 for 3\).*
+
+
+
You've Taught Your Blog to Reject Worthless Things
+
Did you see how inside the class we used the at-symbols? Like this: @time = Time.now
+
Outside the class, we use accessors: entry.time = Time.now But inside we use instance variables: @time = Time.now
+ They're the exact same thing, but expressed in two different places of your program.
+
Your blog now needs a title, a mood and a post in order to work. When a new BlogEntry is created, the initialize method
+ is used to check for any arguments to new. Uh, we need three arguments!
+
Try it again with all three.
+
entry2
+= BlogEntry.new( "I Left my Hoodie on the Mountain!", :confused, "I am
+never going back to that mountain and I hope a giraffe steals it." )
Aha, you're here. And all in one piece. We're still going to make your blog real, but until then, let's review, okay?
+
+
Classes. Everything in Ruby is some kind of object. Classes explain objects. How a certain object works.
+ For example, you made a few blog entry objects and these objects are explained in the BlogEntry class.
+ In other words: you call them BlogEntry objects.
+
Accessors are variables attached to an object which can be used outside the object. (entry.time = Time.now)
+
Instance variables are the same variables you're using for accessors when inside the object.
+ Like in a method definition. (@time = Time.now)
+
+
Okay,
+let's wrap things up, kid. Here's the last chapter of the GRIPPING epic
+story of Try Ruby! Now that you've got a taste of how it all works, how
+are you going to use it around the house and in your grocer's freezer?
+You're a great person (one of my favorites), but you need guidance.
+
Let's finish your blog. You have blog entries, but no actual blog.
+
Put the entries into an array: blog = [entry, entry2]
Some
+beautiful things can be done with the simple parts of Ruby, especially
+when you combine them together into new things. Here we've got a blog
+made of an array of classes. And, actually, Ruby really does good with
+this kind of creature.
+
Here's a few things you can do with your array blog:
+
You'll want to sort your entries from newest to oldest. You can do this with:
+ blog.sort_by { |entry| entry.time }.reverse See the sort_by explanation for more.
+
If you want to search your blog for anything related to "cadillac":
+ blog.find_all { |entry| entry.fulltext.match(/cadillac/i) }
+ Read all about find_all
+ and match
+ to figure out how that works. Also: the slashy /giraffe/i is a Regexp object, used for matching words.
+
Add new entries with blog << new_entry
+ And check out the << method documentation.
One really useful method (I probably use this more than anything else) is map. Type: blog.map { |entry| entry.mood }
+
\[(:\w+, )+:\w+\]
+
+
+
Look at His Face — The Transformation Has Begun
+
The map method cycles through an array and replaces each item with something new. Say you wanted to replace each of your blog entries
+ with the name Bruce Willis. Do it so: blog.map { "Bruce Willis" }
+
Since the block always returns the string "Bruce Willis", that's what you get. In the code you just used, the entry was swapped out
+ for only the entry.mood.
+
Now,
+I want you to make a popup with your blog entries. I'm not going to
+give you all of the code. I'm just going to give you part of it.
+
blog.each do |entry|
+
h2 entry.title
+
p entry.fulltext
+
end
+
+
Now, I expect you to put the popup code around it and add an h1 title with the name of your blog. For extra haroompf, have the time of each entry display.
You are Some Kind of Web Guru, I Have Stars in My Eyes
+
Good,
+that's it! This is exactly the code you can use to write your own real
+Ruby blog. If you're feeling adventurous, I'd check out the Rails videos which show a swift young fellow creating a blog in 15 minutes. You just sit back and watch.
+
I
+should mention Rails. You have been learning the Ruby language, how to
+speak it. But Rails is a bunch of libraries (sort of like the popup
+library we've been using.) It's a very powerful toolkit for building
+websites. If you're interested in learning about Rails, I would head
+ over there right away. Start using your Ruby skills proper!
+
One thing Rails has is easy methods for dates. Like, try: Time.now - 2.weeks
+
class Integer; def weeks; self * 7*24*60*60; end; end
+
\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [-+]\d{4}
+
+
+
If You Want to Start Small
+
If you'd like to start writing little Ruby programs just to practice, I have a project called MouseHole
+ which is a little web toolkit for writing short Ruby programs. You can look over a few
+ scripts to see what I mean.
+
MouseHole
+isn't for writing web sites really. It's just for writing little
+programs you run inside your browser. Like there's a notepad program
+for MouseHole and a program which adds a mouse picture next to links on
+the web which link to MouseHole programs.
+
I've got a MouseHole script inside a file here:
+ print File.read("/MouseHole/flickrpedia.user.rb")
+
.*Inserts Wikipedia links for Flickr tags.*
+
+
+
Summary #8, The Hey-Relax-You-Did-Good Summary
+
This last section took a moment to wind down, to give you some pointers as to how you can use Ruby. If you enjoyed yourself,
+ download Ruby and install it.
Once you have Ruby installed, you can use Interactive Ruby by running irb on your system's prompt. For more on Irb,
+ there's The Tiger's Vest to help you.
+
You
+really deserve a double-layer cake with double-double frosting and a
+guy playing one of those guitars that's a double guitar. I mean you
+finished, you really did! No doubt about it, you're a certified
+red-blooded smartiac!
+
+
+
+
diff --git a/tryruby/app/views/tutorials/intro.rhtml b/app/views/tutorials/intro.rhtml
similarity index 99%
rename from tryruby/app/views/tutorials/intro.rhtml
rename to app/views/tutorials/intro.rhtml
index 4b43137..7443c46 100644
--- a/tryruby/app/views/tutorials/intro.rhtml
+++ b/app/views/tutorials/intro.rhtml
@@ -543,7 +543,7 @@ parts that make up a body.
Quickening it Up
Cool,
-you're blog is awesome. Hey, let's make things a bit easier on you.
+your blog is awesome. Hey, let's make things a bit easier on you.
You're not going to want to set the time like that every time you post.
You just want to type in the title and the entry and the mood quickly,
right?
diff --git a/config.ru b/config.ru
new file mode 100644
index 0000000..73c9258
--- /dev/null
+++ b/config.ru
@@ -0,0 +1,4 @@
+# This file is used by Rack-based servers to start the application.
+
+require ::File.expand_path('../config/environment', __FILE__)
+run Tryruby::Application
diff --git a/config/application.rb b/config/application.rb
new file mode 100644
index 0000000..d12142e
--- /dev/null
+++ b/config/application.rb
@@ -0,0 +1,42 @@
+require File.expand_path('../boot', __FILE__)
+
+require 'rails/all'
+
+# If you have a Gemfile, require the gems listed there, including any gems
+# you've limited to :test, :development, or :production.
+Bundler.require(:default, Rails.env) if defined?(Bundler)
+
+module Tryruby
+ class Application < Rails::Application
+ # Settings in config/environments/* take precedence over those specified here.
+ # Application configuration should go into files in config/initializers
+ # -- all .rb files in that directory are automatically loaded.
+
+ # Custom directories with classes and modules you want to be autoloadable.
+ # config.autoload_paths += %W(#{config.root}/extras)
+
+ # Only load the plugins named here, in the order given (default is alphabetical).
+ # :all can be used as a placeholder for all plugins not explicitly named.
+ # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
+
+ # Activate observers that should always be running.
+ # config.active_record.observers = :cacher, :garbage_collector, :forum_observer
+
+ # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
+ # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
+ # config.time_zone = 'Central Time (US & Canada)'
+
+ # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
+ # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
+ # config.i18n.default_locale = :de
+
+ # JavaScript files you want as :defaults (application.js is always included).
+ # config.action_view.javascript_expansions[:defaults] = %w(jquery rails)
+
+ # Configure the default encoding used in templates for Ruby 1.9.
+ config.encoding = "utf-8"
+
+ # Configure sensitive parameters which will be filtered from the log file.
+ config.filter_parameters += [:password]
+ end
+end
diff --git a/config/boot.rb b/config/boot.rb
new file mode 100644
index 0000000..4489e58
--- /dev/null
+++ b/config/boot.rb
@@ -0,0 +1,6 @@
+require 'rubygems'
+
+# Set up gems listed in the Gemfile.
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
+
+require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
diff --git a/config/database.yml b/config/database.yml
new file mode 100644
index 0000000..07a70ee
--- /dev/null
+++ b/config/database.yml
@@ -0,0 +1,34 @@
+
+development:
+ adapter: mysql2
+ encoding: utf8
+ reconnect: false
+ database: tryruby
+ username: root
+ password:
+ pool: 5
+ timeout: 5000
+ socket: /tmp/mysql.sock
+
+# Warning: The database defined as "test" will be erased and
+# re-generated from your development database when you run "rake".
+# Do not set this db to the same as development or production.
+test:
+ adapter: mysql2
+ database: tryruby_test
+ username: root
+ password:
+ pool: 5
+ timeout: 5000
+ socket: /tmp/mysql.sock
+
+production:
+ adapter: mysql2
+ database: tryruby_production
+ username: root
+ password:
+ pool: 5
+ timeout: 5000
+ socket: /tmp/mysql.sock
+cucumber:
+ <<: *test
diff --git a/config/deploy.rb b/config/deploy.rb
new file mode 100644
index 0000000..36bef48
--- /dev/null
+++ b/config/deploy.rb
@@ -0,0 +1,61 @@
+$:.unshift(File.expand_path('./lib', ENV['rvm_path'])) # Add RVM's lib directory to the load path.
+require "rvm/capistrano" # Load RVM's capistrano plugin.
+set :rvm_ruby_string, 'ree'
+
+require 'bundler/capistrano'
+
+default_run_options[:pty] = true # Must be set for the password prompt from git to work
+set :application, "TryRuby"
+
+default_run_options[:pty] = true # Must be set for the password prompt from git to work
+set :repository, "git@github.com:mosteam/TryRuby.git" # Your clone URL
+set :branch, "master"
+set :scm, "git"
+set :user, "TryRuby" # The server's user for deploys
+set :deploy_to, "/var/rails/TryRuby"
+set :deploy_via, :remote_cache
+set :use_sudo, false
+
+ssh_options[:forward_agent] = true
+
+set :git_shallow_clone, 1
+set :git_enable_submodules, 1
+
+role :web, "106.187.37.16" # Your HTTP server, Apache/etc
+role :app, "106.187.37.16" # This may be the same as your `Web` server
+role :db, "106.187.37.16", :primary => true # This is where Rails migrations will run
+
+# tasks
+namespace :deploy do
+ task :start, :roles => :app do
+ run "touch #{current_path}/tmp/restart.txt"
+ end
+
+ desc "Compile assets"
+ task :assets do
+ run "cd #{current_path}; chmod -R 0777 public/"
+ run "cd #{current_path}; RAILS_ENV=production rake assets:precompile"
+ end
+
+ task :stop, :roles => :app do
+ # Do nothing.
+ end
+
+ desc "Restart Application"
+ task :restart, :roles => :app do
+ run "touch #{current_path}/tmp/restart.txt"
+ run "mkdir -p #{current_path}/tmp/cache"
+ run "cd #{current_path}; chmod -R 0777 log/"
+ run "cd #{current_path}; chmod -R 0777 tmp/"
+ end
+
+ desc "Symlink shared resources on each release"
+ task :symlink_shared, :roles => :app do
+ run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml"
+ run "ln -nfs #{shared_path}/temp #{release_path}/public/temp"
+ # run "ln -nfs #{shared_path}/config/newrelic.yml #{release_path}/config/newrelic.yml"
+ end
+end
+
+after 'deploy:update_code', 'deploy:symlink_shared'
+after "deploy:symlink_shared", "deploy:assets"
\ No newline at end of file
diff --git a/config/environment.rb b/config/environment.rb
new file mode 100644
index 0000000..8e899fa
--- /dev/null
+++ b/config/environment.rb
@@ -0,0 +1,5 @@
+# Load the rails application
+require File.expand_path('../application', __FILE__)
+
+# Initialize the rails application
+Tryruby::Application.initialize!
diff --git a/config/environments/development.rb b/config/environments/development.rb
new file mode 100644
index 0000000..38d039f
--- /dev/null
+++ b/config/environments/development.rb
@@ -0,0 +1,26 @@
+Tryruby::Application.configure do
+ # Settings specified here will take precedence over those in config/application.rb
+
+ # In the development environment your application's code is reloaded on
+ # every request. This slows down response time but is perfect for development
+ # since you don't have to restart the webserver when you make code changes.
+ config.cache_classes = false
+
+ # Log error messages when you accidentally call methods on nil.
+ config.whiny_nils = true
+
+ # Show full error reports and disable caching
+ config.consider_all_requests_local = true
+ config.action_view.debug_rjs = true
+ config.action_controller.perform_caching = false
+
+ # Don't care if the mailer can't send
+ config.action_mailer.raise_delivery_errors = false
+
+ # Print deprecation notices to the Rails logger
+ config.active_support.deprecation = :log
+
+ # Only use best-standards-support built into browsers
+ config.action_dispatch.best_standards_support = :builtin
+end
+
diff --git a/config/environments/production.rb b/config/environments/production.rb
new file mode 100644
index 0000000..fdd5b09
--- /dev/null
+++ b/config/environments/production.rb
@@ -0,0 +1,49 @@
+Tryruby::Application.configure do
+ # Settings specified here will take precedence over those in config/application.rb
+
+ # The production environment is meant for finished, "live" apps.
+ # Code is not reloaded between requests
+ config.cache_classes = true
+
+ # Full error reports are disabled and caching is turned on
+ config.consider_all_requests_local = false
+ config.action_controller.perform_caching = true
+
+ # Specifies the header that your server uses for sending files
+ config.action_dispatch.x_sendfile_header = "X-Sendfile"
+
+ # For nginx:
+ # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'
+
+ # If you have no front-end server that supports something like X-Sendfile,
+ # just comment this out and Rails will serve the files
+
+ # See everything in the log (default is :info)
+ # config.log_level = :debug
+
+ # Use a different logger for distributed setups
+ # config.logger = SyslogLogger.new
+
+ # Use a different cache store in production
+ # config.cache_store = :mem_cache_store
+
+ # Disable Rails's static asset server
+ # In production, Apache or nginx will already do this
+ config.serve_static_assets = false
+
+ # Enable serving of images, stylesheets, and javascripts from an asset server
+ # config.action_controller.asset_host = "http://assets.example.com"
+
+ # Disable delivery errors, bad email addresses will be ignored
+ # config.action_mailer.raise_delivery_errors = false
+
+ # Enable threaded mode
+ # config.threadsafe!
+
+ # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
+ # the I18n.default_locale when a translation can not be found)
+ config.i18n.fallbacks = true
+
+ # Send deprecation notices to registered listeners
+ config.active_support.deprecation = :notify
+end
diff --git a/config/environments/test.rb b/config/environments/test.rb
new file mode 100644
index 0000000..6bf007b
--- /dev/null
+++ b/config/environments/test.rb
@@ -0,0 +1,35 @@
+Tryruby::Application.configure do
+ # Settings specified here will take precedence over those in config/application.rb
+
+ # The test environment is used exclusively to run your application's
+ # test suite. You never need to work with it otherwise. Remember that
+ # your test database is "scratch space" for the test suite and is wiped
+ # and recreated between test runs. Don't rely on the data there!
+ config.cache_classes = true
+
+ # Log error messages when you accidentally call methods on nil.
+ config.whiny_nils = true
+
+ # Show full error reports and disable caching
+ config.consider_all_requests_local = true
+ config.action_controller.perform_caching = false
+
+ # Raise exceptions instead of rendering exception templates
+ config.action_dispatch.show_exceptions = false
+
+ # Disable request forgery protection in test environment
+ config.action_controller.allow_forgery_protection = false
+
+ # Tell Action Mailer not to deliver emails to the real world.
+ # The :test delivery method accumulates sent emails in the
+ # ActionMailer::Base.deliveries array.
+ config.action_mailer.delivery_method = :test
+
+ # Use SQL instead of Active Record's schema dumper when creating the test database.
+ # This is necessary if your schema can't be completely dumped by the schema dumper,
+ # like if you have constraints or database-specific column types
+ # config.active_record.schema_format = :sql
+
+ # Print deprecation notices to the stderr
+ config.active_support.deprecation = :stderr
+end
diff --git a/tryruby/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb
similarity index 61%
rename from tryruby/config/initializers/backtrace_silencers.rb
rename to config/initializers/backtrace_silencers.rb
index c2169ed..59385cd 100644
--- a/tryruby/config/initializers/backtrace_silencers.rb
+++ b/config/initializers/backtrace_silencers.rb
@@ -3,5 +3,5 @@
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
-# You can also remove all the silencers if you're trying do debug a problem that might steem from framework code.
-# Rails.backtrace_cleaner.remove_silencers!
\ No newline at end of file
+# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
+# Rails.backtrace_cleaner.remove_silencers!
diff --git a/tryruby/config/initializers/inflections.rb b/config/initializers/inflections.rb
similarity index 85%
rename from tryruby/config/initializers/inflections.rb
rename to config/initializers/inflections.rb
index d531b8b..9e8b013 100644
--- a/tryruby/config/initializers/inflections.rb
+++ b/config/initializers/inflections.rb
@@ -1,6 +1,6 @@
# Be sure to restart your server when you modify this file.
-# Add new inflection rules using the following format
+# Add new inflection rules using the following format
# (all these examples are active by default):
# ActiveSupport::Inflector.inflections do |inflect|
# inflect.plural /^(ox)$/i, '\1en'
diff --git a/tryruby/config/initializers/mime_types.rb b/config/initializers/mime_types.rb
similarity index 100%
rename from tryruby/config/initializers/mime_types.rb
rename to config/initializers/mime_types.rb
diff --git a/config/initializers/secret_token.rb b/config/initializers/secret_token.rb
new file mode 100644
index 0000000..88f9a7f
--- /dev/null
+++ b/config/initializers/secret_token.rb
@@ -0,0 +1,7 @@
+# Be sure to restart your server when you modify this file.
+
+# Your secret key for verifying the integrity of signed cookies.
+# If you change this key, all old signed cookies will become invalid!
+# Make sure the secret is at least 30 characters and all random,
+# no regular words or you'll be exposed to dictionary attacks.
+Tryruby::Application.config.secret_token = '0b9697ad5c8979de943825eeb25418d1f8cf963ad4e3a6758acc2558ae77b0c097997142fea5c9cb5969f2126ee433aefccbae922c04943ca4074d2c31e9c608'
diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb
new file mode 100644
index 0000000..b4dee00
--- /dev/null
+++ b/config/initializers/session_store.rb
@@ -0,0 +1,8 @@
+# Be sure to restart your server when you modify this file.
+
+Tryruby::Application.config.session_store :cookie_store, :key => '_tryruby_session'
+
+# Use the database for sessions instead of the cookie-based default,
+# which shouldn't be used to store highly confidential information
+# (create the session table with "rails generate session_migration")
+# Tryruby::Application.config.session_store :active_record_store
diff --git a/tryruby/config/locales/en.yml b/config/locales/en.yml
similarity index 89%
rename from tryruby/config/locales/en.yml
rename to config/locales/en.yml
index f265c06..a747bfa 100644
--- a/tryruby/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -2,4 +2,4 @@
# See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
en:
- hello: "Hello world"
\ No newline at end of file
+ hello: "Hello world"
diff --git a/config/routes.rb b/config/routes.rb
new file mode 100644
index 0000000..b0cd5a4
--- /dev/null
+++ b/config/routes.rb
@@ -0,0 +1,68 @@
+Tryruby::Application.routes.draw do
+
+ resources :irb
+
+ # The priority is based upon order of creation:
+ # first created -> highest priority.
+ root :to => "tryruby#index"
+ match '/tryruby/run' => 'tryruby#run'
+ # connect ':controller/:action/:id'
+ # connect ':controller/:action/:id.:format'
+
+ # Sample of regular route:
+ # match 'products/:id' => 'catalog#view'
+ # Keep in mind you can assign values other than :controller and :action
+
+ # Sample of named route:
+ # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
+ # This route can be invoked with purchase_url(:id => product.id)
+
+ # Sample resource route (maps HTTP verbs to controller actions automatically):
+ # resources :products
+
+ # Sample resource route with options:
+ # resources :products do
+ # member do
+ # get 'short'
+ # post 'toggle'
+ # end
+ #
+ # collection do
+ # get 'sold'
+ # end
+ # end
+
+ # Sample resource route with sub-resources:
+ # resources :products do
+ # resources :comments, :sales
+ # resource :seller
+ # end
+
+ # Sample resource route with more complex sub-resources
+ # resources :products do
+ # resources :comments
+ # resources :sales do
+ # get 'recent', :on => :collection
+ # end
+ # end
+
+ # Sample resource route within a namespace:
+ # namespace :admin do
+ # # Directs /admin/products/* to Admin::ProductsController
+ # # (app/controllers/admin/products_controller.rb)
+ # resources :products
+ # end
+
+ # You can have the root of your site routed with "root"
+ # just remember to delete public/index.html.
+ # root :to => "welcome#index"
+
+ # See how all your routes lay out with "rake routes"
+
+ # This is a legacy wild controller route that's not recommended for RESTful applications.
+ # Note: This route will make all actions in every controller accessible via GET requests.
+ # match ':controller(/:action(/:id(.:format)))'
+ end
+
+
+
\ No newline at end of file
diff --git a/db/development.sqlite3 b/db/development.sqlite3
new file mode 100644
index 0000000..e69de29
diff --git a/tryruby/db/seeds.rb b/db/seeds.rb
similarity index 82%
rename from tryruby/db/seeds.rb
rename to db/seeds.rb
index 3174d0c..664d8c7 100644
--- a/tryruby/db/seeds.rb
+++ b/db/seeds.rb
@@ -2,6 +2,6 @@
# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
#
# Examples:
-#
+#
# cities = City.create([{ :name => 'Chicago' }, { :name => 'Copenhagen' }])
-# Major.create(:name => 'Daley', :city => cities.first)
+# Mayor.create(:name => 'Daley', :city => cities.first)
diff --git a/tryruby/doc/README_FOR_APP b/doc/README_FOR_APP
similarity index 100%
rename from tryruby/doc/README_FOR_APP
rename to doc/README_FOR_APP
diff --git a/tryruby/lib/popup.rb b/lib/popup.rb
similarity index 94%
rename from tryruby/lib/popup.rb
rename to lib/popup.rb
index 481fee9..87edf38 100755
--- a/tryruby/lib/popup.rb
+++ b/lib/popup.rb
@@ -7,7 +7,7 @@ module LoadPopup
module Popup
def self.goto(url)
url = url.gsub '"', '\"'
- TryRuby::Output.javascript "window.irb.options.popup_goto(\"#{url}\")"
+ Output.javascript "window.irb.options.popup_goto(\"#{url}\")"
end
class Header
@@ -108,7 +108,7 @@ def self.make(&block)
html = result.generate_html.gsub('\\', '\\\\').gsub('"', '\"')
command = "window.irb.options.popup_make(\"#{html}\")"
- TryRuby::Output.javascript command
+ Tryrubyengine::Output.javascript command
end
end
diff --git a/tryruby/lib/setup.rb b/lib/setup.rb
similarity index 99%
rename from tryruby/lib/setup.rb
rename to lib/setup.rb
index 6bae16a..20fad62 100644
--- a/tryruby/lib/setup.rb
+++ b/lib/setup.rb
@@ -1,4 +1,4 @@
-module TryRuby
+module Tryrubyengine
SetupCode = < 'db:test:prepare'}, 'Run features that should pass') do |t|
+ t.binary = vendored_cucumber_bin # If nil, the gem's binary is used.
+ t.fork = true # You may get faster startup if you set this to false
+ t.profile = 'default'
+ end
+
+ Cucumber::Rake::Task.new({:wip => 'db:test:prepare'}, 'Run features that are being worked on') do |t|
+ t.binary = vendored_cucumber_bin
+ t.fork = true # You may get faster startup if you set this to false
+ t.profile = 'wip'
+ end
+
+ Cucumber::Rake::Task.new({:rerun => 'db:test:prepare'}, 'Record failing features and run only them if any exist') do |t|
+ t.binary = vendored_cucumber_bin
+ t.fork = true # You may get faster startup if you set this to false
+ t.profile = 'rerun'
+ end
+
+ desc 'Run all features'
+ task :all => [:ok, :wip]
+ end
+ desc 'Alias for cucumber:ok'
+ task :cucumber => 'cucumber:ok'
+
+ task :default => :cucumber
+
+ task :features => :cucumber do
+ STDERR.puts "*** The 'features' task is deprecated. See rake -T cucumber ***"
+ end
+rescue LoadError
+ desc 'cucumber rake task not available (cucumber not installed)'
+ task :cucumber do
+ abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin'
+ end
+end
+
+end
diff --git a/lib/tryruby.rb b/lib/tryruby.rb
new file mode 100644
index 0000000..7fe0912
--- /dev/null
+++ b/lib/tryruby.rb
@@ -0,0 +1,206 @@
+#require 'ruby_parser'
+require 'ruby_parser'
+
+require 'stringio'
+require 'popup.rb'
+require 'setup.rb'
+require 'fakefs/safe'
+require 'cgi'
+require 'cgi/session'
+require 'cgi/session/pstore'
+
+
+
+
+
+
+ module Tryrubyengine
+ extend self
+ class TRSession
+ #include ActionDispatch::Session
+ # < TryRuby::Session
+ attr_accessor :cgi, :session
+
+ def initialize
+
+ @session = CGI::Session.new @cgi = CGI.new,
+ 'database_manager' => CGI::Session::PStore, # use PStore
+ 'session_key' => 'trb_sess_id', # custom $session key
+ 'session_expires' => Time.now + 60 * 60, # 60 minute timeout
+ 'prefix' => 'pstore_sid_', #Pstore option
+ 'tmpdir' => 'tmp' # Temp Directory for sessions
+
+ @session['start_time'] ||= Time.now
+ #ActionController::Base.session
+ @session['current_statement'] ||= ''
+ @session['past_commands'] ||= ''
+ end
+
+ def header
+ @cgi.header 'text/plain'
+ end
+
+ [:current_statement, :past_commands, :start_time].each do |accessor|
+ define_method(accessor) { @session[accessor.to_s] }
+ define_method(:"#{accessor.to_s}=") { |new_val| @session[accessor.to_s] = new_val }
+ end
+ end
+
+
+
+ class Output
+ attr_reader :type, :result, :output, :error, :indent_level, :javascript
+
+ def self.standard(params = {})
+ Output.new type: :standard, result: params[:result],
+ output: params[:output] || ''
+ end
+
+ def self.illegal
+ Output.new type: :illegal
+ end
+
+ def self.javascript(js)
+ Output.new type: :javascript, javascript: js
+ end
+
+ def self.no_output
+ Output.standard result: nil
+ end
+
+ def self.line_continuation(level)
+ Output.new type: :line_continuation, indent_level: level
+ end
+
+ def self.error(params = {})
+ params[:error] ||= StandardError.new('TryRuby Error')
+ params[:error].message.gsub! /\(eval\):\d*/, '(TryRuby):1'
+ Output.new type: :error, error: params[:error],
+ output: params[:output] || ''
+ end
+
+ def format
+ case @type
+ when :line_continuation
+ ".." * @indent_level
+ when :error
+ @output + "\033[1;33m#{@error.class}: #{@error.message}"
+ when :illegal
+ "\033[1;33mYou aren't allowed to run that command!"
+ when :javascript
+ "\033[1;JSm#{@javascript}\033[m "
+ else
+ @output + "=> \033[1;20m#{@result.inspect}"
+ end
+ end
+
+ protected
+ def initialize(values = {})
+ values.each do |variable, value|
+ instance_variable_set("@#{variable}", value)
+ end
+ end
+ end
+
+
+ class << self
+ attr_accessor :session
+ Tryrubyengine.session = Tryrubyengine::TRSession.new
+ end
+
+ def calculate_nesting_level(statement)
+ begin
+ RubyParser.new.parse(statement)
+ 0
+ rescue Racc::ParseError => e
+ case e.message
+ when /parse error on value \"\$end\" \(\$end\)/ then
+ new_statement = statement + "\n end"
+ begin
+ RubyParser.new.parse(new_statement)
+ return 1
+ rescue Racc::ParseError => e
+ if e.message =~ /parse error on value \"end\" \(kEND\)/ then
+ new_statement = statement + "\n }"
+ end
+ end
+ begin
+ 1 + calculate_nesting_level(new_statement)
+ rescue Racc::ParseError => e
+ return 1
+ end
+ else
+ raise e
+ end
+ end
+ end
+
+ def run_line(code,session)
+ case code.strip
+ when '!INIT!IRB!'
+ return Output.no_output
+ when 'reset'
+ session.current_statement = ''
+ return Output.no_output
+ when 'time'
+ seconds = (Time.now - session.start_time).ceil
+ return Output.standard result:
+ if seconds < 60; "#{seconds} seconds"
+ elsif seconds < 120; "1 minute"
+ else; "#{seconds / 60} minutes"
+ end
+ end
+
+ # nesting level
+ level = begin
+ calculate_nesting_level(session.current_statement + "\n" + code)
+ rescue Racc::ParseError, SyntaxError
+ 0
+ end
+ if level > 0
+ session.current_statement += "\n" + code
+ return Output.line_continuation(level)
+ end
+
+ # run something
+ FakeFS.activate!
+ stdout_id = $stdout.to_i
+ $stdout = StringIO.new
+ cmd = <<-EOF
+ #{SetupCode}
+ $SAFE = 3
+ #{session.past_commands}
+ $stdout = StringIO.new
+ begin
+ #{session.current_statement}
+ #{code}
+ end
+ EOF
+ begin
+ result = Thread.new { eval cmd, TOPLEVEL_BINDING }.value
+ rescue SecurityError
+ return Output.illegal
+ rescue Exception => e
+ return Output.error :error => e, :output => get_stdout
+ ensure
+ output = get_stdout
+ $stdout = IO.new(stdout_id)
+ FakeFS.deactivate!
+ end
+
+ session.current_statement += "\n" + code
+ session.past_commands += "\n" + session.current_statement.strip
+ session.current_statement = ''
+
+ return result if result.is_a? Output and result.type == :javascript
+ Output.standard result: result, output: output
+ end
+
+ private
+ def get_stdout
+ raise TypeError, "$stdout is a #{$stdout.class}" unless $stdout.is_a? StringIO
+ $stdout.rewind
+ $stdout.read
+ end
+
+ end
diff --git a/log/development.log b/log/development.log
new file mode 100644
index 0000000..ba62c27
--- /dev/null
+++ b/log/development.log
@@ -0,0 +1,15 @@
+DEPRECATION WARNING: config.action_view.debug_rjs will be removed in 3.1, from 3.1 onwards you will need to install prototype-rails to continue to use RJS templates . (called from service at /home/administrator/.rvm/rubies/ruby-1.8.7-p352/lib/ruby/1.8/webrick/httpserver.rb:104)
+
+
+Started GET "/" for 127.0.0.1 at Wed Oct 26 11:13:07 +0800 2011
+ Processing by TryrubyController#index as HTML
+Rendered tryruby/index.html.erb within layouts/tryruby (0.5ms)
+Completed 200 OK in 3ms (Views: 2.7ms | ActiveRecord: 0.0ms)
+
+
+Started GET "/tutorials/intro" for 127.0.0.1 at Wed Oct 26 11:13:07 +0800 2011
+
+ActionController::RoutingError (No route matches "/tutorials/intro"):
+
+
+Rendered /home/administrator/.rvm/gems/ruby-1.8.7-p352/gems/actionpack-3.0.9/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (0.9ms)
diff --git a/public/404.html b/public/404.html
new file mode 100644
index 0000000..9a48320
--- /dev/null
+++ b/public/404.html
@@ -0,0 +1,26 @@
+
+
+
+ The page you were looking for doesn't exist (404)
+
+
+
+
+
+
+
The page you were looking for doesn't exist.
+
You may have mistyped the address or the page may have moved.
+
+
+
diff --git a/public/422.html b/public/422.html
new file mode 100644
index 0000000..83660ab
--- /dev/null
+++ b/public/422.html
@@ -0,0 +1,26 @@
+
+
+
+ The change you wanted was rejected (422)
+
+
+
+
+
+
+
The change you wanted was rejected.
+
Maybe you tried to change something you didn't have access to.
+
+
+
diff --git a/public/500.html b/public/500.html
new file mode 100644
index 0000000..b80307f
--- /dev/null
+++ b/public/500.html
@@ -0,0 +1,26 @@
+
+
+
+ We're sorry, but something went wrong (500)
+
+
+
+
+
+
+
We're sorry, but something went wrong.
+
We've been notified about this issue and we'll take a look at it shortly.
+
+
+
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100644
index 0000000..e69de29
diff --git a/tryruby/public/images/background.png b/public/images/background.png
similarity index 100%
rename from tryruby/public/images/background.png
rename to public/images/background.png
diff --git a/tryruby/public/images/footer.png b/public/images/footer.png
similarity index 100%
rename from tryruby/public/images/footer.png
rename to public/images/footer.png
diff --git a/public/images/header.png b/public/images/header.png
new file mode 100644
index 0000000..d6b9aa0
Binary files /dev/null and b/public/images/header.png differ
diff --git a/public/images/index.html b/public/images/index.html
new file mode 100755
index 0000000..e933af9
--- /dev/null
+++ b/public/images/index.html
@@ -0,0 +1,8 @@
+
+
+
+
+
+
you shouldn't be here.. kicking you out!
+
+
diff --git a/tryruby/public/images/rails.png b/public/images/rails.png
similarity index 100%
rename from tryruby/public/images/rails.png
rename to public/images/rails.png
diff --git a/tryruby/public/images/tile.png b/public/images/tile.png
similarity index 100%
rename from tryruby/public/images/tile.png
rename to public/images/tile.png
diff --git a/tryruby/public/javascripts/application.js b/public/javascripts/application.js
similarity index 100%
rename from tryruby/public/javascripts/application.js
rename to public/javascripts/application.js
diff --git a/tryruby/public/javascripts/console.js b/public/javascripts/console.js
similarity index 100%
rename from tryruby/public/javascripts/console.js
rename to public/javascripts/console.js
diff --git a/tryruby/public/javascripts/controls.js b/public/javascripts/controls.js
similarity index 100%
rename from tryruby/public/javascripts/controls.js
rename to public/javascripts/controls.js
diff --git a/tryruby/public/javascripts/dragdrop.js b/public/javascripts/dragdrop.js
similarity index 100%
rename from tryruby/public/javascripts/dragdrop.js
rename to public/javascripts/dragdrop.js
diff --git a/tryruby/public/javascripts/effects.js b/public/javascripts/effects.js
similarity index 100%
rename from tryruby/public/javascripts/effects.js
rename to public/javascripts/effects.js
diff --git a/public/javascripts/facebox.js b/public/javascripts/facebox.js
new file mode 100755
index 0000000..5ad90ed
--- /dev/null
+++ b/public/javascripts/facebox.js
@@ -0,0 +1,309 @@
+/*
+ * Facebox (for jQuery)
+ * version: 1.2 (05/05/2008)
+ * @requires jQuery v1.2 or later
+ *
+ * Examples at http://famspam.com/facebox/
+ *
+ * Licensed under the MIT:
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * Copyright 2007, 2008 Chris Wanstrath [ chris@ozmm.org ]
+ *
+ * Usage:
+ *
+ * jQuery(document).ready(function() {
+ * jQuery('a[rel*=facebox]').facebox()
+ * })
+ *
+ * Terms
+ * Loads the #terms div in the box
+ *
+ * Terms
+ * Loads the terms.html page in the box
+ *
+ * Terms
+ * Loads the terms.png image in the box
+ *
+ *
+ * You can also use it programmatically:
+ *
+ * jQuery.facebox('some html')
+ * jQuery.facebox('some html', 'my-groovy-style')
+ *
+ * The above will open a facebox with "some html" as the content.
+ *
+ * jQuery.facebox(function($) {
+ * $.get('blah.html', function(data) { $.facebox(data) })
+ * })
+ *
+ * The above will show a loading screen before the passed function is called,
+ * allowing for a better ajaxy experience.
+ *
+ * The facebox function can also display an ajax page, an image, or the contents of a div:
+ *
+ * jQuery.facebox({ ajax: 'remote.html' })
+ * jQuery.facebox({ ajax: 'remote.html' }, 'my-groovy-style')
+ * jQuery.facebox({ image: 'stairs.jpg' })
+ * jQuery.facebox({ image: 'stairs.jpg' }, 'my-groovy-style')
+ * jQuery.facebox({ div: '#box' })
+ * jQuery.facebox({ div: '#box' }, 'my-groovy-style')
+ *
+ * Want to close the facebox? Trigger the 'close.facebox' document event:
+ *
+ * jQuery(document).trigger('close.facebox')
+ *
+ * Facebox also has a bunch of other hooks:
+ *
+ * loading.facebox
+ * beforeReveal.facebox
+ * reveal.facebox (aliased as 'afterReveal.facebox')
+ * init.facebox
+ * afterClose.facebox
+ *
+ * Simply bind a function to any of these hooks:
+ *
+ * $(document).bind('reveal.facebox', function() { ...stuff to do after the facebox and contents are revealed... })
+ *
+ */
+(function($) {
+ $.facebox = function(data, klass) {
+ $.facebox.loading()
+
+ if (data.ajax) fillFaceboxFromAjax(data.ajax, klass)
+ else if (data.image) fillFaceboxFromImage(data.image, klass)
+ else if (data.div) fillFaceboxFromHref(data.div, klass)
+ else if ($.isFunction(data)) data.call($)
+ else $.facebox.reveal(data, klass)
+ }
+
+ /*
+ * Public, $.facebox methods
+ */
+
+ $.extend($.facebox, {
+ settings: {
+ opacity : 0.2,
+ overlay : true,
+ loadingImage : '/facebox/loading.gif',
+ closeImage : '/facebox/closelabel.png',
+ imageTypes : [ 'png', 'jpg', 'jpeg', 'gif' ],
+ faceboxHtml : '\
+
' + rmsg(['Types of values', "What's in a name?"]) +
+ '
'
+ + '
Hi there' + htmlEncode(n)
+ + (n != "!" ? " That's a pretty name. Honest.": "")
+ + " You're getting the hang of this!
" +
+ "
Note: You can chat to Haskell programmers while learning here, enter chat to start it." +
+ " You will join the official IRC channel of the Haskell community!
"
+ + "
Each time, you're getting back the value of the expression. So " +
+ "far, just a number and a list of characters.
" +
+ "
You can have lists of other stuff, too. Let's see your " +
+ " lottery numbers: [42,13,22]
Congratulations, you just used a function." +
+ " They're how you get things done in Haskell." +
+ "
As you might've guessed, we got back " +
+ htmlEncode(result.result)
+ + ".
Ever wanted an evil twin nemesis? Me too. " +
+ "Luckily, you can sort lists of characters, or " +
+ "strings" +
+ ", in the same way as numbers! sort \"chris\"
Good job! You got the age back from the tuple! Didn't " +
+ " even break a sweat, did you? The fst function " +
+ "just gets the first value. It's called \"fst\" because " +
+ "it's used a lot in Haskell so it really needs to be short!
" +
+
+ "
Time to take a rest and see what you learned:
" +
+ "" +
+ "
Functions can be used on lists of any type.
" +
+ "
We can stuff values into tuples.
" +
+ "
Getting the values back from tuples is easy.
" +
+ "" +
+
+ "
Now let's say you want " +
+ " to use a value more than once, how would you do it? " +
+ "To make our lives easier, we can say:
You just bound a variable. " +
+ "That is, you bound x to the expression 4, " +
+ " and then you can write x in some code (the body) and " +
+ " it will mean the same as if you'd written 4.
" +
+
+ "
It's like this: let var = expression in body
" +
+
+ "The in part just separates the expression from the body." +
+
+ "
For example try: " +
+ "let x = 8 * 10 in x + x
" +
+
+ "
So if we wanted to get the age of our villain, we could do:
Well done, that was tricky syntax. You used the (:) " +
+ "function. It takes two values, some value and a list, and " +
+ " constructs a new list" +
+ " out of them. We call it 'cons' for short.
" +
+ "
'a' is " +
+ "the character 'a', [] is an empty list. So " +
+ "tacking 'a' at the start of an empty list just " +
+ "makes a list ['a']!
" +
+ "
But thankfully we don't have to type out " +
+ "'a' : 'b' : [] every time to we want to make a " +
+ "list of characters; we can use " +
+ "syntactic sugar and just write" +
+ " ['a','b']. Don't believe me, check this!
In 'a' : [], : is really just " +
+ " another function, just clever looking.
" +
+ "
Pretty functions like this are written like (:) when " +
+ " you talk about them.
" +
+ "
A list of characters ['a','b'] can just be written " +
+ "\"ab\". Much easier!
"
+ + "" +
+ "
Phew! You're getting pretty deep! Your arch nemesis, " +
+ nemesis + ", is gonna try to steal your " + rmsg(['mojo',
+ 'pizza']) +
+ "! Let's learn a bit more about functions and passing " +
+ "them around. Try this:
That's so cool! You described a simple function square and then " +
+ "you just passed it to another function (map) and got back " +
+ htmlEncode(result.value) + ", exactly what you expected!
" +
+
+ "
Haskell is pretty good at composing things together like this. " +
+ "Some other things you can try are:
" +
+
+ "
" +
+ "
let add1 x = x + 1 in map add1 [1,5,7]
" +
+ "
let take5s = filter (==5) in take5s [1,5,2,5,3,5]
" +
+ "
let take5s = filter (==5) in map take5s [[1,5],[5],[1,1]]
" +
+ "
" +
+
+ "
Did you get back what you expected?
" +
+
+ "
One more example for text; how do you upcase a letter?
So you had a value (10,12) and matched " +
+ "it against a pattern (a,b), then you were able" +
+ " to do stuff with the a and b!" +
+
+ "
Note: Pattern matching (a,b) against " +
+ "(1,2) to get the a is the same as" +
+ " doing fst (1,2), like you did in step7!
" +
+
+ "
A pattern always matches the way the " +
+ "value was originally constructed. Remember that \"abc\" is " +
+ "syntactic sugar for 'a' : 'b' : 'c' : [].
" +
+
+ "
So you can get the characters from a string with patterns:
" + rmsg(["Types", "What's in a Type?", "Types & Values"]) + "
" +
+ "
What's this? Something new!
" +
+
+ "
In Haskell there are types of values. Every value belongs to a type. To demonstrate this fact, I've sneakily enabled types to be " +
+ "shown of every value in the console from now on.
" +
+
+ "
The type of the value 'a' is Char (short for 'character', but you guessed that, right?).
" +
+
+ "
You've seen the type of a character, now what about" +
+ " a list of characters?
Remember this one? I know you do! fst (1,2) is 1, right?
" +
+ "
We read its type
" +
+ "
fst :: (a, b) -> a
" +
+ "
as: for all types a and b, the fst has type (a,b) to a. So the fst " +
+ "function works on a pair of values of any types! We call such a function polymorphic." +
+ "
" +
+ "
Remember the drop function? Maybe you don't. I don't! Let's check out its type:
This is something new. You've got two arrows! Relax. You can read
" +
+ "
a -> b -> c as a -> (b -> c)
" +
+
+ "
In other words, drop is a function from integers (Int values) to functions of lists to lists ([a] -> [a] values). Drop is a function to another function.
You've got a function of type [a] -> [a]! The drop function is considered a multi-parameter function. Remember the map function? Its parameters were a function and a list. Just another multi-parameter function.
" +
+
+ "
You can add another parameter and, hey presto, you get a list!