├── .ruby-version ├── source ├── javascripts │ └── application.js ├── stylesheets │ ├── print.css.scss │ ├── screen-old-ie.css.scss │ ├── screen.css.scss │ └── govuk-frontend.css ├── images │ ├── shiba-inu.jpg │ ├── lesson-2 │ │ ├── ruby.png │ │ ├── brøther.jpg │ │ ├── image1.png │ │ └── poignant-guide.gif │ ├── puppy-in-a-hat.jpg │ ├── lesson-1 │ │ ├── image2.png │ │ ├── image3.png │ │ ├── image4.png │ │ ├── image5.png │ │ ├── image6.png │ │ └── image7.png │ ├── lesson-3 │ │ ├── developer-tools.png │ │ ├── finished-application.png │ │ ├── developer-tools-network.png │ │ └── developer-tools-network-focused.png │ └── ccheart_black.svg ├── index.html.md.erb ├── setting-up-your-computer.html.md.erb ├── accessibility.html.md.erb ├── lesson-2-ruby-and-the-command-line.html.md.erb ├── lesson-3-writing-ruby-scripts.html.md.erb ├── lesson-4-ruby-on-the-web.html.md.erb └── lesson-1-html-and-css.html.md.erb ├── .template_version ├── .gitignore ├── Gemfile ├── .github ├── workflows │ └── main.yml └── dependabot.yml ├── config.rb ├── config └── tech-docs.yml ├── README.md └── Gemfile.lock /.ruby-version: -------------------------------------------------------------------------------- 1 | 3.1.3 2 | -------------------------------------------------------------------------------- /source/javascripts/application.js: -------------------------------------------------------------------------------- 1 | //= require govuk_tech_docs 2 | -------------------------------------------------------------------------------- /source/stylesheets/print.css.scss: -------------------------------------------------------------------------------- 1 | $is-print: true; 2 | 3 | @import "govuk_tech_docs"; 4 | -------------------------------------------------------------------------------- /source/images/shiba-inu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alphagov/learn-to-code/HEAD/source/images/shiba-inu.jpg -------------------------------------------------------------------------------- /source/stylesheets/screen-old-ie.css.scss: -------------------------------------------------------------------------------- 1 | $is-ie: true; 2 | $ie-version: 8; 3 | 4 | @import "govuk_tech_docs"; 5 | -------------------------------------------------------------------------------- /source/images/lesson-2/ruby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alphagov/learn-to-code/HEAD/source/images/lesson-2/ruby.png -------------------------------------------------------------------------------- /source/images/puppy-in-a-hat.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alphagov/learn-to-code/HEAD/source/images/puppy-in-a-hat.jpg -------------------------------------------------------------------------------- /source/images/lesson-1/image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alphagov/learn-to-code/HEAD/source/images/lesson-1/image2.png -------------------------------------------------------------------------------- /source/images/lesson-1/image3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alphagov/learn-to-code/HEAD/source/images/lesson-1/image3.png -------------------------------------------------------------------------------- /source/images/lesson-1/image4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alphagov/learn-to-code/HEAD/source/images/lesson-1/image4.png -------------------------------------------------------------------------------- /source/images/lesson-1/image5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alphagov/learn-to-code/HEAD/source/images/lesson-1/image5.png -------------------------------------------------------------------------------- /source/images/lesson-1/image6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alphagov/learn-to-code/HEAD/source/images/lesson-1/image6.png -------------------------------------------------------------------------------- /source/images/lesson-1/image7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alphagov/learn-to-code/HEAD/source/images/lesson-1/image7.png -------------------------------------------------------------------------------- /source/images/lesson-2/brøther.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alphagov/learn-to-code/HEAD/source/images/lesson-2/brøther.jpg -------------------------------------------------------------------------------- /source/images/lesson-2/image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alphagov/learn-to-code/HEAD/source/images/lesson-2/image1.png -------------------------------------------------------------------------------- /source/images/lesson-2/poignant-guide.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alphagov/learn-to-code/HEAD/source/images/lesson-2/poignant-guide.gif -------------------------------------------------------------------------------- /source/images/lesson-3/developer-tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alphagov/learn-to-code/HEAD/source/images/lesson-3/developer-tools.png -------------------------------------------------------------------------------- /.template_version: -------------------------------------------------------------------------------- 1 | --- 2 | :remote: https://github.com/alphagov/tech-docs-template.git 3 | :revision: 50a4afee728247bd56fbf457efa1497776ff1181 4 | -------------------------------------------------------------------------------- /source/images/lesson-3/finished-application.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alphagov/learn-to-code/HEAD/source/images/lesson-3/finished-application.png -------------------------------------------------------------------------------- /source/images/lesson-3/developer-tools-network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alphagov/learn-to-code/HEAD/source/images/lesson-3/developer-tools-network.png -------------------------------------------------------------------------------- /source/images/lesson-3/developer-tools-network-focused.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alphagov/learn-to-code/HEAD/source/images/lesson-3/developer-tools-network-focused.png -------------------------------------------------------------------------------- /source/stylesheets/screen.css.scss: -------------------------------------------------------------------------------- 1 | @import "govuk_tech_docs"; 2 | 3 | .footer__licence-logo { 4 | width: 41px; 5 | height: 36px; 6 | background-image: url(/images/ccheart_black.svg); 7 | background-size: 41px 36px; 8 | } 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile ~/.gitignore_global 6 | 7 | # Ignore bundler config 8 | /.bundle 9 | 10 | # Ignore the build directory 11 | /build 12 | 13 | # Ignore cache 14 | /.sass-cache 15 | /.cache 16 | 17 | # Ignore .DS_store file 18 | .DS_Store 19 | 20 | Staticfile.auth 21 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # If you do not have OpenSSL installed, change 2 | # the following line to use 'http://' 3 | source 'https://rubygems.org' 4 | 5 | # For environments that don't have a JS runtime (https://github.com/rails/execjs) 6 | gem "mini_racer" 7 | 8 | # For faster file watcher updates on Windows: 9 | gem 'wdm', '~> 0.1.0', platforms: [:mswin, :mingw] 10 | 11 | # Windows does not come with time zone data 12 | gem 'tzinfo-data', platforms: [:mswin, :mingw, :jruby] 13 | 14 | # Include the tech docs gem 15 | gem 'govuk_tech_docs' 16 | 17 | # Add syntax highlighting 18 | gem 'middleman-syntax' 19 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Delivery 2 | 3 | on: 4 | workflow_dispatch: {} 5 | push: 6 | branches: 7 | - master 8 | pull_request: 9 | 10 | jobs: 11 | build: 12 | permissions: 13 | contents: write 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: ruby/setup-ruby@v1 # version read from `.ruby-version` file 18 | with: 19 | bundler-cache: true 20 | 21 | - name: Build 22 | run: | 23 | bundle install 24 | bundle exec middleman build 25 | 26 | - name: Deploy 27 | uses: peaceiris/actions-gh-pages@v3 28 | with: 29 | github_token: ${{ secrets.GITHUB_TOKEN }} 30 | publish_dir: ./build 31 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: bundler 4 | directory: / 5 | schedule: 6 | interval: daily 7 | allow: 8 | # Security updates 9 | - dependency-name: brakeman 10 | dependency-type: direct 11 | # Internal gems 12 | - dependency-name: "govuk*" 13 | dependency-type: direct 14 | - dependency-name: rubocop-govuk 15 | dependency-type: direct 16 | # Framework gems 17 | - dependency-name: jasmine 18 | dependency-type: direct 19 | - dependency-name: rails 20 | dependency-type: direct 21 | - dependency-name: rspec-rails 22 | dependency-type: direct 23 | - dependency-name: sass-rails 24 | dependency-type: direct 25 | -------------------------------------------------------------------------------- /source/index.html.md.erb: -------------------------------------------------------------------------------- 1 | --- 2 | title: Learn to Code 3 | weight: 1 4 | --- 5 | 6 | # Learn to Code 7 | 8 | The Government Digital Service is a diverse organisation, with lots of people 9 | with lots of different skills. Some people who work at GDS are professional 10 | software engineers, but many others have never written any code. 11 | 12 | This documentation contains tutorials that are intended to take an absolute 13 | beginner through the basics of writing code. 14 | 15 | ## Acknowledgements and Licence 16 | 17 | The content of these tutorials has been adapted from several sources. In particular: 18 | 19 | - [Codebar](https://github.com/codebar/tutorials) (CC BY-NC-SA 4.0) 20 | - [jumpstartlab](http://tutorials.jumpstartlab.com/projects/ruby_in_100_minutes.html) (CC BY-NC-SA 3.0) 21 | - [_why's (Poignant) Guide to Ruby](https://poignant.guide/) (CC BY-SA 2.5) 22 | 23 | All additional content is released under the creative commons [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc/4.0/) 24 | licence. 25 | -------------------------------------------------------------------------------- /config.rb: -------------------------------------------------------------------------------- 1 | require 'govuk_tech_docs' 2 | require 'find' 3 | 4 | GovukTechDocs.configure(self) 5 | 6 | class CreativeCommonsFooter < ::Middleman::Extension 7 | def initialize(app, options_hash={}, &block) 8 | super 9 | end 10 | 11 | def after_build(builder) 12 | build_dir = app.config[:build_dir] 13 | Find.find(build_dir) do |f| 14 | if f.end_with? '.html' 15 | content = File.read(f) 16 | patched_content = content.gsub( 17 | 'https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/', 18 | 'https://creativecommons.org/licenses/by-nc/4.0/', 19 | ).gsub( 20 | 'Open Government Licence v3.0', 21 | 'Creative Commons CC BY-NC-SA 4.0 Licence', 22 | ) 23 | File.write(f, patched_content) 24 | end 25 | end 26 | end 27 | end 28 | 29 | Middleman::Extensions.register :creative_commons_footer do 30 | CreativeCommonsFooter 31 | end 32 | 33 | activate :creative_commons_footer 34 | 35 | set :relative_links, true 36 | activate :relative_assets 37 | -------------------------------------------------------------------------------- /config/tech-docs.yml: -------------------------------------------------------------------------------- 1 | # Host to use for canonical URL generation (without trailing slash) 2 | host: https://alphagov.github.io/learn-to-code 3 | 4 | # Header-related options 5 | show_govuk_logo: false 6 | service_name: Learn to Code 7 | service_link: / 8 | phase: Beta 9 | 10 | # Links to show on right-hand-side of header 11 | header_links: {} 12 | footer_links: 13 | Accessibility: /accessibility.html 14 | 15 | # Enables search functionality. This indexes pages only and is not recommended for single-page sites. 16 | enable_search: true 17 | 18 | # Tracking ID from Google Analytics (e.g. UA-XXXX-Y) 19 | ga_tracking_id: null 20 | 21 | # Enable multipage navigation in the sidebar 22 | multipage_nav: true 23 | 24 | # Enable collapsible navigation in the sidebar 25 | collapsible_nav: true 26 | 27 | # Table of contents depth – how many levels to include in the table of contents. 28 | # If your ToC is too long, reduce this number and we'll only show higher-level 29 | # headings. 30 | max_toc_heading_level: 3 31 | 32 | # Prevent robots from indexing (e.g. whilst in development) 33 | prevent_indexing: false 34 | 35 | show_contribution_banner: true 36 | github_repo: alphagov/learn-to-code 37 | -------------------------------------------------------------------------------- /source/setting-up-your-computer.html.md.erb: -------------------------------------------------------------------------------- 1 | --- 2 | title: Setting up your computer 3 | weight: 2 4 | --- 5 | 6 | # Setting up your computer 7 | 8 | If you’re using a Mac, most of the software you need for these lessons is already installed. 9 | 10 | ## Text editor (Visual Studio Code) 11 | 12 | Programmers use **text editors** to write code. You could use Notepad (Windows) 13 | or TextEdit (Mac) to write code. However most programmers use a text editor 14 | with programming-specific features: 15 | 16 | * **Syntax highlighting** shows your code in different colours. This helps you spot 17 | any errors, and understand the structure of your code. 18 | * **Auto-indent** helps you keep your code tidy. 19 | * **Project navigation and tabs** helps you move between the different files in 20 | your project. 21 | * **Auto-completion** shows you keywords you could use to finish what you’re 22 | typing, so you don’t have to remember all the possible commands. 23 | 24 | We recommend you use [Visual Studio Code for the Web](https://vscode.dev) for this because it provides a zero-install experience running entirely in your browser. 25 | 26 | ## Terminal and Ruby 27 | 28 | macOs comes with a built in terminal, and a version of the ruby programming 29 | language. If you're not using a mac you can follow the instructions on the ruby website: 30 | 31 | [https://www.ruby-lang.org/en/documentation/installation/](https://www.ruby-lang.org/en/documentation/installation/) 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Learn to Code 2 | ==================== 3 | 4 | Government Digital Service is a diverse organisation, with lots of people 5 | with lots of different skills. Some people who work at GDS are professional 6 | software engineers, but many have never written any code. 7 | 8 | This repo contains tutorials that are intended to take an absolute beginner 9 | through the basics of writing code. 10 | 11 | Status 12 | ------ 13 | 14 | :woman_technologist: Under active development :man_technologist: 15 | 16 | Following a successful :airplane: pilot :airplane: of three 1 hour sessions in 17 | the first quarter of 2019, we have continued developing these sessions based on 18 | feedback from students and retrospectives with coaches. 19 | 20 | The second iteration involved three 2 hour sessions in the third quarter of 2019. 21 | 22 | The current format is four 2 hour sessions, which will run in the first quarter 23 | of 2020. 24 | 25 | Rough plan 26 | ---------- 27 | 28 | Since we've only got three sessions we're going to stick to the basics. Initially I'm thinking something like the following: 29 | 30 | ### Introduction to HTML and CSS 31 | 32 | In which we build and style a little webpage 33 | 34 | Can maybe use design system so it feels like more of an achievement? 35 | 36 | ### Introduction to the command line and ruby 37 | 38 | Introduce using the terminal and ruby 39 | 40 | irb for testing ruby expressions 41 | 42 | ### Writing Ruby scripts 43 | 44 | ruby blah.rb will run scripts 45 | 46 | More advanced Ruby functionality 47 | 48 | ### Introduction to HTTP and running code on the web 49 | 50 | little webrick server that serves HTML / CSS etc. Webrick is nice because we can do it without installing any dependencies. 51 | 52 | Can build a form that takes input and does the same thing as the previous exercise. 53 | 54 | # Out of scope 55 | 56 | - git 57 | - any terminal things beyond the essential (ls, cd, irb, ruby)? 58 | 59 | Influences 60 | ---------- 61 | 62 | - [Codebar](https://github.com/codebar/tutorials) (CC BY-NC-SA 4.0) 63 | - [Rails Girls](https://github.com/railsgirls/railsgirls.github.io) (CC BY-SA 3.0) 64 | - [Django Girls](https://github.com/DjangoGirls/tutorial) (CC BY-SA 4.0) 65 | - [Node Girls](https://github.com/node-girls/) (MIT License) 66 | -------------------------------------------------------------------------------- /source/images/ccheart_black.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /source/accessibility.html.md.erb: -------------------------------------------------------------------------------- 1 | --- 2 | title: Accessibility statement for Learn to Code technical documentation 3 | last_reviewed_on: 2020-09-03 4 | review_in: 6 months 5 | hide_in_navigation: true 6 | --- 7 | 8 | # Accessibility statement for Learn to Code 9 | 10 | This accessibility statement applies to the Learn to Code technical documentation at [https://alphagov.github.io/learn-to-code](https://alphagov.github.io/learn-to-code/#learn-to-code). 11 | 12 | This website is run by the developer community at Government Digital Service (GDS). We want as many people as possible to be able to use this website. For example, that means you should be able to: 13 | 14 | + change colours, contrast levels and fonts 15 | + zoom in up to 300% without problems 16 | + navigate most of the website using just a keyboard 17 | + navigate most of the website using speech recognition software 18 | + listen to most of the website using a screen reader (including the most recent versions of JAWS, NVDA and VoiceOver) 19 | 20 | We’ve also made the website text as simple as possible to understand. 21 | 22 | [AbilityNet](https://mcmw.abilitynet.org.uk/) has advice on making your device easier to use if you have a disability. 23 | 24 | ## How accessible this website is 25 | 26 | We know some parts of this website are not fully accessible for the following reasons: 27 | 28 | - some pages have redundant links 29 | - there are issues caused by our Technical Documentation Template 30 | 31 | ## Feedback and contact information 32 | 33 | If you need any part of this service in a different format like large print, audio recording or braille, contact the GOV.UK Notify team at [https://www.notifications.service.gov.uk/support](https://www.notifications.service.gov.uk/support). 34 | 35 | We’ll aim to get back to you within 3 working days. 36 | 37 | ## Reporting accessibility problems with this website 38 | 39 | We’re always looking to improve the accessibility of this website. If you find any problems not listed on this page or think we’re not meeting accessibility requirements, contact the GOV.UK Notify team at [https://www.notifications.service.gov.uk/support](https://www.notifications.service.gov.uk/support). 40 | 41 | ## Enforcement procedure 42 | 43 | The Equality and Human Rights Commission (EHRC) is responsible for enforcing the Public Sector Bodies (Websites and Mobile Applications) (No. 2) Accessibility Regulations 2018 44 | (the ‘accessibility regulations’). If you’re not happy with how we respond to your complaint, [contact the Equality Advisory and Support Service (EASS)](https://www.equalityadvisoryservice.com/). 45 | 46 | ## Technical information about this website’s accessibility 47 | 48 | GDS is committed to making its website accessible, in accordance with the Public Sector Bodies (Websites and Mobile Applications) (No. 2) Accessibility Regulations 2018. 49 | 50 | ## Compliance status 51 | 52 | This website is partially compliant with the [Web Content Accessibility Guidelines version 2.1](https://www.w3.org/TR/WCAG21/) AA standard, due to the non-compliances listed below. 53 | 54 | ### Non-accessible content 55 | 56 | The content listed below is non-accessible for the following reasons. 57 | 58 | #### Non-compliance with the accessibility regulations 59 | 60 | Some pages have redundant links. This is not a fail, but should be looked at under [WCAG 2.1 success criterion 2.4.4 Link Purpose (In Context)](https://www.w3.org/TR/UNDERSTANDING-WCAG20/navigation-mechanisms-refs.html). 61 | 62 | Also, some parts of this website are not fully accessible because of [issues caused by our Technical Documentation Template](https://tdt-documentation.london.cloudapps.digital/accessibility/#using-the-technical-documentation-template-for-your-own-documentation). 63 | 64 | ## How we tested this website 65 | 66 | We last tested this website for accessibility issues in August 2020. 67 | 68 | We used manual and automated tests to look for issues such as: 69 | 70 | - lack of keyboard accessibility 71 | - link text that’s not descriptive 72 | - non-unique or non-hierarchical headings 73 | - italics, bold or block capital formatting 74 | - inaccessible formatting in general 75 | - inaccessible language 76 | - inaccessible diagrams or images 77 | - lack of colour contrast for text, important graphics and controls 78 | - images not having meaningful alt text 79 | - problems when using assistive technologies such as screen readers and screen magnifiers 80 | 81 | ## What we’re doing to improve accessibility 82 | 83 | We plan to look at the redundant links and fix the accessibility issues with the Technical Documentation Template by the end of March 2021. 84 | 85 | We plan to look at the linked PDF documents to maximise accessibility by the end of 2020. 86 | 87 | ## Preparation of this accessibility statement 88 | 89 | This statement was prepared on 3 September 2020. It was last reviewed on 31 December 2020. 90 | 91 | This website was last tested in August 2020. The test was carried out by the technical writing team at GDS. We used the [WAVE Web Accessibility Evaluation Tool](https://wave.webaim.org/) and a checklist we created with the help of the GDS accessibility team. We tested all of the website's pages. 92 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | activesupport (7.0.8.1) 5 | concurrent-ruby (~> 1.0, >= 1.0.2) 6 | i18n (>= 1.6, < 2) 7 | minitest (>= 5.1) 8 | tzinfo (~> 2.0) 9 | addressable (2.8.6) 10 | public_suffix (>= 2.0.2, < 6.0) 11 | autoprefixer-rails (10.4.16.0) 12 | execjs (~> 2) 13 | backports (3.24.1) 14 | chronic (0.10.2) 15 | chunky_png (1.4.0) 16 | coffee-script (2.4.1) 17 | coffee-script-source 18 | execjs 19 | coffee-script-source (1.12.2) 20 | commonmarker (0.23.10) 21 | compass (1.0.3) 22 | chunky_png (~> 1.2) 23 | compass-core (~> 1.0.2) 24 | compass-import-once (~> 1.0.5) 25 | rb-fsevent (>= 0.9.3) 26 | rb-inotify (>= 0.9) 27 | sass (>= 3.3.13, < 3.5) 28 | compass-core (1.0.3) 29 | multi_json (~> 1.0) 30 | sass (>= 3.3.0, < 3.5) 31 | compass-import-once (1.0.5) 32 | sass (>= 3.2, < 3.5) 33 | concurrent-ruby (1.2.3) 34 | contracts (0.16.1) 35 | dotenv (3.0.2) 36 | em-websocket (0.5.3) 37 | eventmachine (>= 0.12.9) 38 | http_parser.rb (~> 0) 39 | erubis (2.7.0) 40 | eventmachine (1.2.7) 41 | execjs (2.9.1) 42 | fast_blank (1.0.1) 43 | fastimage (2.3.0) 44 | ffi (1.16.3) 45 | govuk_tech_docs (3.5.0) 46 | autoprefixer-rails (~> 10.2) 47 | chronic (~> 0.10.2) 48 | haml (< 6.0.0) 49 | middleman (~> 4.0) 50 | middleman-autoprefixer (~> 2.10.0) 51 | middleman-compass (>= 4.0.0) 52 | middleman-livereload 53 | middleman-search-gds 54 | middleman-sprockets (~> 4.0.0) 55 | middleman-syntax (~> 3.2.0) 56 | nokogiri 57 | openapi3_parser (~> 0.9.0) 58 | redcarpet (~> 3.5.1) 59 | haml (5.2.2) 60 | temple (>= 0.8.0) 61 | tilt 62 | hamster (3.0.0) 63 | concurrent-ruby (~> 1.0) 64 | hashie (3.6.0) 65 | http_parser.rb (0.8.0) 66 | i18n (1.6.0) 67 | concurrent-ruby (~> 1.0) 68 | kramdown (2.4.0) 69 | rexml 70 | libv8-node (18.16.0.0-x86_64-linux) 71 | listen (3.8.0) 72 | rb-fsevent (~> 0.10, >= 0.10.3) 73 | rb-inotify (~> 0.9, >= 0.9.10) 74 | memoist (0.16.2) 75 | middleman (4.5.1) 76 | coffee-script (~> 2.2) 77 | haml (>= 4.0.5) 78 | kramdown (>= 2.3.0) 79 | middleman-cli (= 4.5.1) 80 | middleman-core (= 4.5.1) 81 | middleman-autoprefixer (2.10.0) 82 | autoprefixer-rails (>= 9.1.4) 83 | middleman-core (>= 3.3.3) 84 | middleman-cli (4.5.1) 85 | thor (>= 0.17.0, < 1.3.0) 86 | middleman-compass (4.0.1) 87 | compass (>= 1.0.0, < 2.0.0) 88 | middleman-core (>= 4.0.0) 89 | middleman-core (4.5.1) 90 | activesupport (>= 6.1, < 7.1) 91 | addressable (~> 2.4) 92 | backports (~> 3.6) 93 | bundler (~> 2.0) 94 | contracts (~> 0.13, < 0.17) 95 | dotenv 96 | erubis 97 | execjs (~> 2.0) 98 | fast_blank 99 | fastimage (~> 2.0) 100 | hamster (~> 3.0) 101 | hashie (~> 3.4) 102 | i18n (~> 1.6.0) 103 | listen (~> 3.0) 104 | memoist (~> 0.14) 105 | padrino-helpers (~> 0.15.0) 106 | parallel 107 | rack (>= 1.4.5, < 3) 108 | sassc (~> 2.0) 109 | servolux 110 | tilt (~> 2.0.9) 111 | toml 112 | uglifier (~> 3.0) 113 | webrick 114 | middleman-livereload (3.4.7) 115 | em-websocket (~> 0.5.1) 116 | middleman-core (>= 3.3) 117 | rack-livereload (~> 0.3.15) 118 | middleman-search-gds (0.11.2) 119 | execjs (~> 2.6) 120 | middleman-core (>= 3.2) 121 | nokogiri (~> 1.6) 122 | middleman-sprockets (4.0.0) 123 | middleman-core (~> 4.0) 124 | sprockets (>= 3.0) 125 | middleman-syntax (3.2.0) 126 | middleman-core (>= 3.2) 127 | rouge (~> 3.2) 128 | mini_racer (0.8.0) 129 | libv8-node (~> 18.16.0.0) 130 | minitest (5.22.2) 131 | multi_json (1.15.0) 132 | nokogiri (1.16.2-x86_64-linux) 133 | racc (~> 1.4) 134 | openapi3_parser (0.9.2) 135 | commonmarker (~> 0.17) 136 | padrino-helpers (0.15.3) 137 | i18n (>= 0.6.7, < 2) 138 | padrino-support (= 0.15.3) 139 | tilt (>= 1.4.1, < 3) 140 | padrino-support (0.15.3) 141 | parallel (1.24.0) 142 | parslet (2.0.0) 143 | public_suffix (5.0.4) 144 | racc (1.7.3) 145 | rack (2.2.8.1) 146 | rack-livereload (0.3.17) 147 | rack 148 | rb-fsevent (0.11.2) 149 | rb-inotify (0.10.1) 150 | ffi (~> 1.0) 151 | redcarpet (3.5.1) 152 | rexml (3.2.6) 153 | rouge (3.30.0) 154 | sass (3.4.25) 155 | sassc (2.4.0) 156 | ffi (~> 1.9) 157 | servolux (0.13.0) 158 | sprockets (4.2.1) 159 | concurrent-ruby (~> 1.0) 160 | rack (>= 2.2.4, < 4) 161 | temple (0.10.3) 162 | thor (1.2.2) 163 | tilt (2.0.11) 164 | toml (0.3.0) 165 | parslet (>= 1.8.0, < 3.0.0) 166 | tzinfo (2.0.6) 167 | concurrent-ruby (~> 1.0) 168 | uglifier (3.2.0) 169 | execjs (>= 0.3.0, < 3) 170 | webrick (1.8.1) 171 | 172 | PLATFORMS 173 | x86_64-linux 174 | 175 | DEPENDENCIES 176 | govuk_tech_docs 177 | middleman-syntax 178 | mini_racer 179 | tzinfo-data 180 | wdm (~> 0.1.0) 181 | 182 | BUNDLED WITH 183 | 2.3.26 184 | -------------------------------------------------------------------------------- /source/lesson-2-ruby-and-the-command-line.html.md.erb: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Lesson 2: Ruby and the Command Line" 3 | weight: 4 4 | --- 5 | 6 | # Lesson 2: Ruby and the Command Line 7 | 8 | ## Introduction for this lesson 9 | 10 | ### Objectives 11 | 12 | In this tutorial we are going to look at: 13 | 14 | * what a command line is 15 | * how to use the command line to navigate the file system and run programs 16 | * what Ruby is 17 | * numbers and strings 18 | * how to use variables 19 | * calling and defining methods 20 | 21 | ### Goal 22 | 23 | By the end of this tutorial you will have learnt how to navigate through the 24 | command line and how to run some basic operations in Ruby. 25 | 26 | ## Introduction to the command line 27 | 28 | ### What is the command line? 29 | 30 | The command line is a text interface for your computer. Similar to Windows Explorer on Windows or Finder on a Mac, it lets you navigate through the files and folders of your computer - but it is completely text based. The command line works by typing commands against a prompt, which then gets passed to the operating system of the computer that runs these commands. 31 | 32 | ### How do I access the command line? 33 | 34 | On a Mac you can access the command line by opening the Terminal application 35 | from the Applications > Utilities folder (or use `cmd (⌘) + space` and search 36 | for "Terminal"). 37 | 38 | The command line can seem unfamiliar and scary, but it's really a different way of interacting with your computer. This tutorial only covers safe commands that will not do anything bad to your computer, even if you get them wrong. 39 | 40 | ### Navigating around in the terminal 41 | 42 | Once you've opened up your terminal you should see a window that has says "Last login" with a date after it, and a cursor next to a dollar sign. 43 | 44 | ![](/images/lesson-2/image1.png) 45 | 46 | Do not worry if the text in yours is a little different - it does not matter. 47 | 48 | Basic commands are written on a single line, and run when you press the `Enter` button on your keyboard. 49 | 50 | Try typing, then pressing `Enter`: 51 | 52 | ```shell 53 | pwd 54 | ``` 55 | 56 | #### `pwd` or print working directory 57 | 58 | The `pwd` command prints to the command line the current directory (another name for folder) you are in. If you have just opened up your terminal, you are probably in your "home" directory, and should get an output similar to this: 59 | 60 | ``` 61 | /Users/your-username 62 | ``` 63 | 64 | So your current "working directory" is `/Users/your-username`. 65 | 66 | #### Getting things wrong on the command line 67 | 68 | If you type a command that the command line does not understand, it will show you an error message. Do not panic if you see one of these - everything is fine! Take a look at the command you wrote and see if you can work out what was wrong. 69 | 70 | Try this for example: 71 | 72 | ```shell 73 | whargleblargle 74 | ``` 75 | 76 | You should see an error message like `-bash: whargleblargle: command not found`. 77 | 78 | If you want to cancel your current entry, you can either delete the command using the backspace button, or press `Ctrl + C` to get a brand new line. Your mouse will not work for navigating around the command line commands - but you can use the arrow keys on your keyboard to move the cursor left and right. 79 | 80 | #### `ls` or list 81 | 82 | You might wonder "how I do know which files are in a directory?", the `ls` command can do this: 83 | 84 | ```shell 85 | ls 86 | ``` 87 | 88 | This should print a list of the files and folders inside the working 89 | directory. You'll probably see directories like `Applications`, `Desktop`, 90 | `Documents` and `Downloads`. 91 | 92 | ### `cd` or change directory 93 | 94 | The `cd` command allows you to move between directories. You tell `cd` which directory to move to by putting the path after the `cd`, like this: 95 | 96 | ```shell 97 | cd Desktop 98 | ``` 99 | 100 | Lots of commands need parameters like this - for example, `cd` needs to know the directory to move to, while `pwd` does not. We call the parameters "arguments". 101 | 102 | ### Task 1: change to the directory containing your code 103 | 104 | In Lesson 1 we created a folder to keep our source code 105 | (`lesson-1-html-and-css`). Create a new folder for lesson 2 called 106 | `lesson-2-ruby` and change the working directory in your command line using 107 | `cd`. 108 | 109 | Confirm you're in the right place by running: 110 | 111 | ```shell 112 | pwd 113 | ``` 114 | 115 | and check what files there are in this directory by running: 116 | 117 | ```shell 118 | ls 119 | ``` 120 | 121 | There probably will not be any files because we have not created any yet. 122 | 123 | #### Notes 124 | 125 | In Finder you can copy the path to a directory by right clicking, holding 126 | down the option key (`⌥`), and choosing *Copy "Directory" as Pathname*. 127 | Alternatively, you can drag the folder onto the terminal and it will type 128 | the path for you. 129 | 130 | If your directory includes spaces (or other weird characters) you might 131 | need to put it in quotes so the command line does not get confused. So: 132 | 133 | ```bash 134 | $ cd '/Users/your-username/My Directory With Spaces/lesson-2-ruby' 135 | ``` 136 | 137 | instead of 138 | 139 | ```bash 140 | $ cd /Users/your-username/My Directory With Spaces/lesson-2-ruby 141 | ``` 142 | 143 | ## Introduction to Ruby 144 | 145 | Ruby is a programming language. For a beginner, Ruby is very similar to other 146 | languages like Python, JavaScript and PHP. The basic skills you learn in Ruby 147 | will translate directly into many other languages. 148 | 149 | As well as being a wonderful language, Ruby has a vibrant, friendly, and 150 | sometimes weird community of people. That means there's lots of great 151 | resources for learning, and lots of places where you can get help. 152 | 153 | ### Running Ruby interactively with `irb` 154 | 155 | There are two ways to run Ruby from the command line: 156 | 157 | * Interactively with `irb` (Interactive Ruby) 158 | * Running a file with `ruby` itself 159 | 160 | To start with, let's look at `irb`. We'll get on to how to run a file later. 161 | 162 | `irb` is lets us write bits of Ruby and quickly see what they evaluate to. 163 | 164 | Start `irb` by running: 165 | 166 | ```shell 167 | irb 168 | ``` 169 | 170 | Your command line prompt will change from `$ ` to `irb(main):001:0> `. You can then write Ruby code into the command line. 171 | 172 | When you want to leave irb and go back to your command prompt type `exit` and press enter. 173 | 174 | ### Numbers 175 | 176 | We can use Ruby as a kind of calculator. Try typing `1 + 1` into irb and 177 | pressing enter. Do you get the right answer? 178 | 179 | In Ruby, the `+` operator adds numbers together. Other operators include: 180 | 181 | * `-` - subtract 182 | * `*` - multiply 183 | * `/` - divide 184 | * `**` - raise to the power of 185 | 186 | You can also use brackets (`()`) to group things, e.g. `(2 + 2) / 2` which would evaluate to 2, rather than `2 + 2 / 2` which would evaluate to 3. 187 | 188 | #### Task 2: Maths challenge 189 | 190 | Use `irb` to work out the answer to "191 multiplied by 7". 191 | 192 |
193 | Answer 194 | 195 | ``` 196 | irb(main):016:0> 191 * 7 197 | => 1337 198 | ``` 199 | 200 |
201 | 202 | ### Strings 203 | 204 | In the real world strings tie things up. Programming strings have *nothing* 205 | to do with real-world strings. 206 | 207 | Programming strings are used to store collections of letters and numbers. 208 | That could be a single letter like `"a"`, a word like `"hi"`, or a sentence like 209 | `"Hello my friends."`. 210 | 211 | A Ruby string is written as a quote (`"`) followed by some letters, numbers, 212 | or symbols and ended with a closing quote (`"`). The shortest possible string 213 | is called the empty string: `""`. It’s not uncommon for a single string to 214 | contain paragraphs or even pages of text. 215 | 216 | If you type a string into `irb` it will return it back at you: 217 | 218 | ``` 219 | irb(main):017:0> "Hello IRB" 220 | => "Hello IRB" 221 | ``` 222 | 223 | #### Getting things wrong in IRB 224 | 225 | Just like in the command line, if you give `irb` a command it does not understand it will show you an error message. Again, do not panic! Everything is fine. 226 | 227 | `irb` will do its best to explain why it did not understand your Ruby, but sometimes the error messages can be hard for a beginner to understand. 228 | 229 | For example: 230 | 231 | ``` 232 | irb(main):018:0> "Hello IRB" + 7 233 | TypeError: no implicit conversion of Fixnum into String 234 | from (irb):1:in `+' 235 | from (irb):1 236 | from /usr/bin/irb:11:in `
' 237 | ``` 238 | 239 | Here, `irb` is telling us that you're not allowed to add strings and numbers 240 | together in Ruby. 241 | 242 | ### Variables 243 | 244 | Programming is all about creating abstractions, and in order to create an 245 | abstraction we must be able to assign names to things. Variables are a way of 246 | creating a name for a piece of data. 247 | 248 | Creating variables in Ruby uses a single equals sign - `name` `=` `value`. Some examples: 249 | 250 | ```ruby 251 | name = "Fido" 252 | age_human_years = 4 253 | age_dog_years = age_human_years * 7 254 | ``` 255 | 256 | This would give three variables: `name` with a value of `"Fido"`, `age_human_years` with a value of `4` and `age_dog_years` with a value of `28`. 257 | 258 | Variable names in Ruby have to start with a letter, and they can not contain spaces or "special" characters like `-`, `$`, `@` and `&`. 259 | 260 | As a style convention, Ruby variables use underscores to separate the bits of 261 | the name - this is called `snake_case` (as opposed to `camelCase` or `PascalCase` which are used elsewhere). 262 | 263 | #### Task 3: Set and use a variable 264 | 265 | Use `irb` to set a variable called `answer` to the value of `7` multiplied by 266 | `6`. Multiply the `answer` variable by `10` in `irb` to see what happens. 267 | 268 |
269 | Answer 270 | 271 | ``` 272 | irb(main):020:0> answer = 7 * 6 273 | => 42 274 | irb(main):021:0> answer * 10 275 | => 420 276 | irb(main):022:0> answer 277 | => 42 278 | ``` 279 | 280 |
281 | 282 | 283 | ### String interpolation 284 | 285 | We often need to build a string out of other strings and bits of Ruby. In 286 | Ruby we can do this with "string interpolation". 287 | 288 | Within the string we use the interpolation marker `#{}`. Inside those 289 | brackets we can put any variables or Ruby code which will be evaluated, 290 | converted to a string, and output in that spot of the outer string. 291 | 292 | ``` 293 | irb(main):019:0> "The dog #{name} is #{age_human_years} human years old, which is #{age_dog_years} in dog years." 294 | => "The dog Fido is 4 human years old, which is 28 in dog years." 295 | ``` 296 | 297 | > Note: on a Mac you can enter the `#` key with option (`⌥`) + 3 298 | 299 | #### Task 4: Use string interpolation 300 | 301 | Using string interpolation in `irb`, create a string with the text: 302 | 303 | > "The answer to life, the universe and everything is ..." 304 | 305 | Where `...` is the value of the `answer` variable you set in Task 3. 306 | 307 |
308 | Answer 309 | 310 | ``` 311 | irb(main):023:0> answer = 7 * 6 312 | => 42 313 | irb(main):024:0> "The answer to life, the universe and everything is #{answer}" 314 | => "The answer to life, the universe and everything is 42" 315 | ``` 316 | 317 |
318 | 319 | 320 | ### Calling methods 321 | 322 | While programming, we often find ourselves doing the same thing over and over again. It would be nice if we could give a particular task a name, and run it by calling its name. 323 | 324 | In Ruby we do this with *methods*, and there are lots of them already built 325 | into the language. One example is `rand`, which generates a random number: 326 | 327 | ``` 328 | irb(main):025:0> rand 329 | => 0.11487911496307956 330 | ``` 331 | 332 | If we want to generate a random number less than a particular number, we can 333 | provide our maximum to `rand` as an "argument": 334 | 335 | ``` 336 | irb(main):026:0> rand(100) 337 | => 7 338 | irb(main):027:0> rand(100) 339 | => 43 340 | ``` 341 | 342 | You can also call some methods on things by using a `.` like this: 343 | 344 | ``` 345 | irb(main):028:0> "make me louder".upcase 346 | => "MAKE ME LOUDER" 347 | irb(main):029:0> "em esrever".reverse 348 | => "reverse me" 349 | ``` 350 | 351 | #### Task 5: Decode a secret message 352 | 353 | Decode this top secret, encrypted message: 354 | 355 | ``` 356 | !gniog peeK !llew repus gniod er'uoY 357 | ``` 358 | 359 | (Hint: it's not Welsh - it's been reversed) 360 | 361 |
362 | Answer 363 | 364 | ``` 365 | irb(main):030:0> "!gniog peeK !llew repus gniod er'uoY".reverse 366 | => "You're doing super well! Keep going!" 367 | ``` 368 | 369 |
370 | -------------------------------------------------------------------------------- /source/lesson-3-writing-ruby-scripts.html.md.erb: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Lesson 3: Writing Ruby Scripts" 3 | weight: 5 4 | --- 5 | 6 | # Lesson 3: Writing Ruby Scripts 7 | 8 | ## Introduction 9 | 10 | ### Objectives 11 | 12 | In this tutorial we are going to look at: 13 | 14 | * getting user input 15 | * doing things multiple times using loops 16 | * building simple programs 17 | * using `require` to access other Ruby modules 18 | * using Ruby's `Date` type 19 | * using `File` to read files in Ruby 20 | 21 | ### Goal 22 | 23 | By the end of this tutorial you will have used what you learnt in lesson 2 to 24 | build a couple of small Ruby programs, including one like [this times tables game](https://repl.it/@RichardTowers/TimesTablesGame). 25 | 26 | ### Running a file with Ruby 27 | 28 | We've been having fun with `irb` in Lesson 2 - it's a great tool for exploring and 29 | learning about Ruby. Ideally though we'd like to be able to save our programs 30 | for later, and run them whenever we want. 31 | 32 | To do this, we can write a Ruby script in a text editor (like you did with HTML in 33 | lesson 1), then run the script from the command line with `ruby name-of-your-script.rb`. 34 | 35 | Ruby files end with the extension `.rb`. 36 | 37 | #### Task 1: My first Ruby script 38 | 39 | * Exit `irb` by running the `exit` command 40 | * Create a file in your text editor (we recommended Visual Studio Code in lesson 1) called `hello.rb` 41 | * Confirm you can see the file in the command line by running `ls` 42 | * From the command line, use Ruby to run your file by typing `ruby hello.rb` and pressing enter 43 | * You should see nothing returned (because `hello.rb` is empty at the moment) 44 | 45 | ### Interacting with the user 46 | 47 | Now that we're running our Ruby from a file, we can't rely on `irb` to handle 48 | all of our user input and output. When we want to show something to the user 49 | we need to explicitly say so, and likewise, when we want some input from the 50 | user we have to explicitly ask for it. 51 | 52 | Ruby provides a `puts` method (put string) and a `gets` method (get 53 | string). 54 | 55 | * `puts` - prints a string to the command line 56 | * `gets` - waits for the user to type one line of text into the command line, 57 | when they press enter, returns whatever the user typed (so you can store it 58 | in a variable) 59 | 60 | #### Task 2: Hello world! 61 | 62 | Add the following to your `hello.rb` file, save it, and run it with `ruby hello.rb`: 63 | 64 | ```ruby 65 | puts("What is your name?") 66 | name = gets 67 | puts("Hello #{name}") 68 | ``` 69 | 70 | We can use `puts` and `gets` to create a very simple text based user interface. 71 | 72 | #### Getting things wrong in Ruby scripts 73 | 74 | Just like `irb`, if you get something wrong in a Ruby script Ruby will tell 75 | you by printing an error message. Nothing to worry about - programmers make 76 | mistakes all the time. 77 | 78 | Imagine a script called `oops.rb` containing: 79 | 80 | ```ruby 81 | puts("time for a deliberate error") 82 | oops("this won't work") 83 | ``` 84 | 85 | When you run this with `ruby oops.rb` you'll get an error like this: 86 | 87 | ``` 88 | time for a deliberate error 89 | oops.rb:2:in `
': undefined method `oops' for main:Object (NoMethodError) 90 | ``` 91 | 92 | The `oops.rb:2` bit at the start tells us what file the error was in, and 93 | what line (2 in this case) the error was on. There's no method called `oops` 94 | so Ruby doesn't know what to do. 95 | 96 | #### Task 3: Create a script that reverses the input 97 | 98 | Create a new script called `reverse.rb` in your text editor. 99 | 100 | Use `gets` to get a string from the user, use `.reverse` to reverse that string, 101 | and use `puts` to print it. 102 | 103 |
104 | Answer 105 | 106 | ```ruby 107 | puts("Enter a string to reverse: ") 108 | input = gets 109 | puts("Your string reversed is: ") 110 | puts(input.reverse) 111 | ``` 112 | 113 |
114 | 115 | #### Task 4: Create a script that multiplies two numbers 116 | 117 | Create a new script called `multiply.rb` in your text editor. 118 | 119 | Note that `gets` gets the user input as a `string`. In Ruby strings and 120 | numbers are *not the same* (`"42"` is not equal to `42`). 121 | 122 | When you need to ask the user for a number you must ask them for a string and 123 | then convert it into a number using `.to_i` like so: 124 | 125 | ```ruby 126 | user_input_as_string = gets 127 | user_input_as_number = user_input_as_string.to_i 128 | ``` 129 | 130 | The `i` in `.to_i` stands for "integer" which is fancy way of saying 131 | "whole number". 132 | 133 | Use `gets`, `.to_i` and `puts` to get two strings from the user, 134 | converts them to numbers, multiplies them together and prints the result. 135 | 136 |
137 | Answer 138 | 139 | ```ruby 140 | puts("Enter the first number:") 141 | x_string = gets 142 | x_number = x_string.to_i 143 | puts("Enter the second number:") 144 | y_string = gets 145 | y_number = y_string.to_i 146 | puts("#{x_number} * #{y_number} = #{x_number * y_number}") 147 | ``` 148 | 149 |
150 | 151 | 152 | 153 | ### Defining methods 154 | 155 | The Ruby authors didn't manage to write every method we'll ever need into 156 | Ruby itself, so sometimes we need to define our own. 157 | 158 | This means we can write abstractions that describe what we're doing and we 159 | don't have to repeat ourselves. 160 | 161 | Earlier, we had this line of code: 162 | 163 | ```ruby 164 | age_dog_years = age_human_years * 7 165 | ``` 166 | 167 | This is okay, but it's a little surprising to see that `7` in there - what's 168 | it doing? It would be nicer if we could write: 169 | 170 | ```ruby 171 | age_dog_years = convert_to_dog_years(age_human_years) 172 | ``` 173 | 174 | and hide away the grubby implementation details inside a method. 175 | 176 | In Ruby a method definition looks like this: 177 | 178 | ```ruby 179 | def method_name(argument) 180 | result = "some value" 181 | return result 182 | end 183 | ``` 184 | 185 | You can name a method anything you could name a variable (they're 186 | `snake_cased` by convention too). They can have as many lines of code inside 187 | them as you want. 188 | 189 | #### Task 5: Create a script that converts human years to dog years 190 | 191 | Create a script called `dog-years.rb`. Use `puts`, `gets` and `.to_i` 192 | to ask the user how old their dog is. 193 | 194 | Assuming that dogs age faster than humans, and that there are seven "dog 195 | years" to one "human year", define a method which: 196 | 197 | * takes an age in human years as a argument 198 | * multiplies the age in human years by seven 199 | * returns the result of the multiplication 200 | 201 | Call the method in your script, and print the result. 202 | 203 |
204 | Answer 205 | 206 | ```ruby 207 | def convert_to_dog_years(age) 208 | return age * 7 209 | end 210 | 211 | puts("How old is your dog in human years?") 212 | age_human_years_string = gets 213 | age_human_years_number = age_human_years_string.to_i 214 | 215 | age_dog_years = convert_to_dog_years(age_human_years_number) 216 | puts("Your dog is #{age_dog_years} in dog years") 217 | ``` 218 | 219 |
220 | 221 | ### Repeating things 222 | 223 | Meme where a cat looks at a bowl of fruit loops, and says 'brøether, may i have the lööps' 224 | 225 | So far, each line of code we've written has run exactly once (each time a 226 | script runs). Ruby goes through each line in the script, runs it, then moves 227 | on to the next line. When it reaches the end of the file, the script exits. 228 | 229 | One of the things that computers are really good at is repeating themselves. 230 | In Ruby we can use methods like `loop` and `.times` to make the computer 231 | repeat things. 232 | 233 | You might want to try some of the following out in `irb` to get a feel for 234 | how they work. (If you get stuck in a loop in `irb` you can escape it by 235 | pressing `ctrl + c`): 236 | 237 | ```ruby 238 | 5.times do 239 | puts("Odelay!") 240 | end 241 | ``` 242 | 243 | ```ruby 244 | 10.times do |i| 245 | puts("#{10 - i} green bottles, hanging on the wall,") 246 | puts("#{10 - i} green bottles, hanging on the wall,") 247 | puts("And if one green bottle should accidentally fall,") 248 | puts("There'll be #{9 - i} green bottles hanging on the wall.") 249 | puts 250 | end 251 | ``` 252 | 253 | ```ruby 254 | loop do 255 | puts("What's your name?") 256 | name = gets 257 | puts("Hello #{name} (to exit this infinite loop, press ctrl+c)") 258 | end 259 | ``` 260 | 261 | The bit between the `do` and the `end` is called a block, which is run by the 262 | method repeatedly. Blocks can take parameters after the `do`, which are 263 | wrapped in vertical pipes like `|i|`. 264 | 265 | #### Task 6: Update one of your scripts to work in a loop 266 | 267 | Earlier, you wrote a few scripts that ask the user for some input, do 268 | something with the input then print the result and exit. Change one of these 269 | scripts (e.g. `multiply.rb`) so they do this in an infinite loop (using `loop`). 270 | 271 | If you get stuck in an infinite loop (a loop which never ends) in the command 272 | line you can break out by pressing `ctrl + c`. 273 | 274 |
275 | Answer 276 | 277 | ```ruby 278 | loop do 279 | puts("Enter the first number:") 280 | x_string = gets 281 | x_number = x_string.to_i 282 | puts("Enter the second number:") 283 | y_string = gets 284 | y_number = y_string.to_i 285 | puts("#{x_number} * #{y_number} = #{x_number * y_number}") 286 | end 287 | ``` 288 | 289 |
290 | 291 | ### Conditionals 292 | 293 | One last thing to learn is how to get the computer to do something based on 294 | some condition. To do this, we can use the `if` statement, like so: 295 | 296 | ```ruby 297 | puts("What is your name?") 298 | name = gets 299 | if name.include?("r") 300 | puts("Hi #{name} - you sound like a pretty cool person") 301 | else 302 | puts("Hi nerd") 303 | end 304 | ``` 305 | 306 | An `if` statement takes a "condition" (something that evaluates 307 | to `true` or `false`). You can use things like `==` (equals), `<` (less than), 308 | or methods like `.include?` (like we did in the example). 309 | 310 | Note that we use `==` instead of `=` to compare two values. This is because 311 | `==` tests if two values are equal, whereas `=` assigns the value on the right 312 | to the variable on the left. 313 | 314 | If the condition is true Ruby will run the lines of code between 315 | the `if` and the `else`, otherwise Ruby will run the lines of code between 316 | the `else` and the `end`. 317 | 318 | ### Tying it all together 319 | 320 | Phew! That was a lot to learn. To recap, we've learned: 321 | 322 | * how to use `irb` 323 | * how to use numbers 324 | * what "strings" are and how to use them 325 | * how to use variables to name things 326 | * how to "interpolate" strings 327 | * how to call methods 328 | * how to run Ruby from a file 329 | * how to interact with a user 330 | * how to define methods 331 | * how to repeat things 332 | * how to do things conditionally 333 | 334 | If you've understood all of that, well done! You now know the basics of 335 | programming. There's a lot more to learn, but it all builds on these 336 | fundamentals. 337 | 338 | To tie everything you've learned together, here's one final "hard" task. 339 | 340 | #### Task 7: Build a times tables game 341 | 342 | Right at the beginning, we said you'd build [this times tables game](https://repl.it/@RichardTowers/TimesTablesGame). 343 | 344 | To do this you'll need to use everything you've just learned. It's a pretty 345 | difficult problem for a beginner, so if you get stuck on something don't be 346 | afraid to ask for help. 347 | 348 | Here's a rough plan of how to implement this: 349 | 350 | * create a `score` variable to keep track of the users score 351 | * in a loop that happens 4 times 352 | * generate two numbers between 1 and 12 using `rand` and assign them to variables 353 | * print a message to the user asking them to multiply the numbers together 354 | * get the user's answer and covert it to a number (using `.to_i`) 355 | * compare the user's answer to the answer Ruby thinks is correct 356 | * show the user a message saying whether they're correct (and add one to their score) 357 | * if the user scored 4 then show them a message saying they got them all right 358 | * otherwise, show the user a message commiserating them for their failure 359 | 360 | For bonus points, consider whether you could define a method to do some of 361 | the work to make the loop easier to read. 362 | 363 |
364 | Answer 365 | 366 | ```ruby 367 | def multiplication_challenge 368 | x = rand(12) + 1 369 | y = rand(12) + 1 370 | 371 | print("What is #{x} multiplied by #{y} ? ") 372 | user_input = gets 373 | user_input_as_a_number = user_input.to_i 374 | 375 | correct_answer = x * y 376 | if user_input_as_a_number == correct_answer 377 | puts(":) correct!") 378 | return true 379 | else 380 | puts(":( oops!") 381 | puts("The answer was #{correct_answer}") 382 | return false 383 | end 384 | end 385 | 386 | number_of_rounds = 4 387 | score = 0 388 | 389 | puts("Times tables challenge") 390 | puts("----------------------") 391 | puts 392 | puts("You will be asked #{number_of_rounds} questions.") 393 | puts("Press enter to start...") 394 | gets 395 | 396 | number_of_rounds.times do |i| 397 | if multiplication_challenge 398 | score = score + 1 399 | end 400 | end 401 | 402 | if score == number_of_rounds 403 | puts("You scored #{score}/#{number_of_rounds}. Well done!") 404 | else 405 | puts("You scored #{score}/#{number_of_rounds}. Better luck next time!") 406 | end 407 | ``` 408 | 409 |
410 | 411 | ### Using `require` to access other Ruby modules 412 | 413 | In lesson 2 we used a number of built-in Ruby methods, like `rand` (to get 414 | a random number), `.reverse` (to reverse a string), `gets` and 415 | `puts` (to read and write strings from the command line). 416 | 417 | These methods are so useful that they live in the core of Ruby, so you can 418 | always call them. 419 | 420 | Some bits of Ruby are used less often, and these are not included by default. 421 | To use these other bits you need to `require` them. For example, the `"date"` 422 | module lets you work with dates and times, but it isn't included by default. 423 | 424 | Running `require("date")` includes the date code so you can use it in your 425 | script. For example: 426 | 427 | ``` 428 | irb(main):001:0> require("date") 429 | => true 430 | irb(main):002:0> Date.today 431 | => # 432 | ``` 433 | 434 | ### Working with Dates in Ruby 435 | 436 | Ruby's date type makes doing things like adding days to a date much easier 437 | (if you didn't have a date type you'd need to worry about how many days there 438 | are in a month and so on). 439 | 440 | ``` 441 | irb(main):003:0> one_thousand_days_in_the_future = Date.today + 1000 442 | => # 443 | ``` 444 | 445 | The `.today` method gets today's date, but you can also create dates for 446 | other days using `.new`: 447 | 448 | ``` 449 | irb(main):004:0> Date.new(2022, 2, 23) 450 | => # 451 | ``` 452 | 453 | Because different cultures represent dates in different ways (e.g. Japan use 454 | 2019-05-30, the USA use 05/30/2019 and the UK use 30/05/2019), there's a 455 | special method for formatting dates as strings called `.strftime`. It takes 456 | a "format" string as an argument specifying how to show the date: 457 | 458 | ``` 459 | irb(main):005:0> japan_format = Date.today.strftime("%Y-%m-%d") 460 | => "2019-05-30" 461 | irb(main):006:0> usa_format = Date.today.strftime("%m/%d/%Y") 462 | => "05/30/2019" 463 | irb(main):007:0> uk_format = Date.today.strftime("%d/%m/%Y") 464 | => "30/05/2019" 465 | ``` 466 | 467 | There are lots of placeholders you can use in your date string, including: 468 | 469 | * `%Y` - the year as a 4 digit number 470 | * `%m` - the month as a 2 digit number 471 | * `%d` - the day as a 2 digit number 472 | * `%A` - the day of the week as a word (e.g. Thursday) 473 | 474 | #### Task 1: What day were you born on? 475 | 476 | Using `irb` and the `Date` type, work out what day of the week you were born on. 477 | 478 |
479 | Answer 480 | 481 | ``` 482 | irb(main):001:0> require("date") 483 | => true 484 | 485 | irb(main):002:0> birthday = Date.new(1988, 1, 20) 486 | => # 487 | 488 | irb(main):003:0> birthday.strftime("%A") 489 | => "Wednesday" 490 | ``` 491 | 492 |
493 | 494 | ### Using `File` to read files in Ruby 495 | 496 | Sometimes it's nice to be able to store things in files, and read these files 497 | using Ruby so we can do something with the contents. Ruby has a `File.read` 498 | method that lets us do this. 499 | 500 | `File.read` takes the path to the file as an argument, and returns the 501 | contents of the file as a string. 502 | 503 | ``` 504 | irb(main):004:0> File.read("/Users/your-username/Desktop/lesson-1-html-and-css/index.html") 505 | => "\n... 506 | ``` 507 | 508 | We can work with the contents using all the string methods (like 509 | `.reverse`) we've already seen. 510 | 511 | There are lots of other useful methods like `.size` (which returns how many 512 | characters there are in the string), and `.sub` (which takes two arguments, 513 | and substitutes the first occurence of the first string with the second). 514 | 515 | ``` 516 | irb(main):005:0> "Cats are the best".sub("Cat", "Dog") 517 | => "Dogs are the best" 518 | irb(main):006:0> "Dogs are the best".size 519 | => 17 520 | ``` 521 | 522 | #### Task 2: count the characters in a file 523 | 524 | We created a file in `lesson-1-html-and-css/index.html`. Use `File.read` 525 | and `.size` to work out how many characters there are in the file. 526 | 527 | > In Finder you can copy the path to a directory by right clicking, holding 528 | down the option key (`⌥`), and choosing *Copy "Directory" as Pathname*. 529 | Alternatively, you can drag the folder onto the terminal and it will type 530 | the path for you. 531 | 532 |
533 | Answer 534 | 535 | ``` 536 | irb(main):006:0> file = File.read("/Users/your-username/Desktop/lesson-1-html-and-css/index.html") 537 | => "\n... 538 | irb(main):007:0> file.size 539 | 1260 540 | ``` 541 | 542 |
543 | 544 | 545 | ## Further reading 546 | 547 | If you learn best from _weird_ books then [_why's (poignant) guide](https://poignant.guide/) 548 | is excellent (see cartoon below). If you'd prefer something less silly, have a look at: 549 | 550 | * [Learn to Program](https://pine.fm/LearnToProgram/) 551 | * [Learn Ruby The Hard Way](https://learnrubythehardway.org/book/) 552 | * [Ruby Koans](http://rubykoans.com/) 553 | 554 | Which are all great. 555 | 556 | ![A comic strip from _why's (poignant) guide showing Dr. Cham lost in some tunnels under a mysterious castle](/images/lesson-2/poignant-guide.gif) 557 | -------------------------------------------------------------------------------- /source/lesson-4-ruby-on-the-web.html.md.erb: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Lesson 4: Ruby on the Web" 3 | weight: 6 4 | --- 5 | 6 | # Lesson 4: Ruby on the Web 7 | 8 | ## Introduction 9 | 10 | ### Objectives 11 | 12 | In this tutorial we are going to look at: 13 | 14 | * what HTTP is and how it works 15 | * using Google Chrome's Developer tools to inspect HTTP requests 16 | * building a web server with Ruby 17 | * templating HTML 18 | * introducing web security 19 | 20 | ### Goal 21 | 22 | By the end of this tutorial you will have built an "Apply for a barking permit" webpage: 23 | 24 | Apply for a Barking Permit website, showing the form from lesson 1 and the confirmation page 25 | 26 | 27 | You'll have a basic understanding of how web applications work, and a good foundation to build on. 28 | 29 | ## Introduction to HTTP 30 | 31 | ### What is HTTP? 32 | 33 | HTTP stands for HyperText Transfer Protocol. 34 | 35 | HTTP describes the format of the communications between your web browser and 36 | a "web server" (which is just a kind of computer). 37 | 38 | Your browser sends HTTP requests and the server responds with HTTP responses. 39 | 40 | For example, when you visit `www.gov.uk` your browser will send a request a like this: 41 | 42 | ```http 43 | GET / HTTP/1.1 44 | Host: www.gov.uk 45 | ``` 46 | 47 | And GOV.UK's server will respond with something like: 48 | 49 | ``` 50 | HTTP/1.1 200 OK 51 | Date: Wed, 29 May 2019 12:08:17 GMT 52 | Content-Type: text/html; charset=UTF-8 53 | Content-Length: 32897 54 | 55 | 56 | 57 | ... snip ... 58 | 59 | ``` 60 | 61 | In this case the response contains the HTML of the GOV.UK homepage. 62 | 63 | ### Viewing HTTP requests using browser developer tools 64 | 65 | Modern browsers come with built in tools that let you see what's happening 66 | under the hood. In Google Chrome on a Mac you can bring these up for any 67 | webpage by pressing Command + Option + I (`⌘ + ⌥ + I`). 68 | 69 | ![Screenshot showing the Google Chrome developer tools on www.gov.uk](/images/lesson-3/developer-tools.png) 70 | 71 | The Network tab shows you the requests and responses your browser is sending and receiving. 72 | 73 | #### Task 3: Use the developer tools to look at an HTTP request 74 | 75 | Go to any website you like and use the developer tools to look at the first 76 | HTTP request it makes. 77 | 78 |
79 | Answer (screenshots) 80 | 81 | ![Screenshot showing the Google Chrome developer tools network tab](/images/lesson-3/developer-tools-network.png) 82 | ![Screenshot showing the Google Chrome developer tools focused on a particular request](/images/lesson-3/developer-tools-network-focused.png) 83 | 84 |
85 | 86 | ## Building web servers with Ruby 87 | 88 | ### What is a web server? 89 | 90 | A web server is a computer program that can understand HTTP requests and 91 | respond to them with HTTP responses. 92 | 93 | In lesson 1 we built a website which sent the same HTML back for every 94 | request. By getting Ruby involved in handling the request we can make our 95 | website dynamic (so the response is not always the same). We can also perform 96 | side effects in response to certain requests (like sending emails, or 97 | printing out physical barking permits). 98 | 99 | Ruby is a great language to get started with, because it has everything you 100 | need to build simple web servers built right in to the language. 101 | 102 | First of all, let's create some files for us to serve. 103 | 104 | #### Task 4: Create files and directories 105 | 106 | * Create a folder called `lesson-4-ruby-on-the-web` next to your other lesson folders. 107 | * Inside this folder, create another folder called `public`, and copy [the images folder from lesson 1](/lesson-1-html-and-css.html#element-image-img) inside. 108 | 109 | You should end up with a directory structure like: 110 | 111 | ``` 112 | lesson-4-ruby-on-the-web 113 | └── public 114 | └── images 115 | ├── puppy-in-a-hat.jpg 116 | └── shiba-inu.jpg 117 | ``` 118 | 119 | ### Hello WEBrick! 120 | 121 | Earlier we `require`'d `"date"` so we could do some things with dates which 122 | are not in the core ruby language. Similarly, we can require a thing called 123 | `"webrick"` which allows us to build HTTP servers. 124 | 125 | We can use WEBrick to create a new server by calling the 126 | `WEBrick::HTTPServer.new` method like this: 127 | 128 | ```ruby 129 | require("webrick") 130 | server = WEBrick::HTTPServer.new(Port: 8080, DocumentRoot: './public') 131 | ``` 132 | 133 | This might look a bit confusing because it uses some bits of Ruby we haven't 134 | introduced yet (what are all these colons doing all of a sudden?). Do not 135 | worry about it - at some point you'll learn about modules, classes, and named 136 | arguments and it will all make sense. 137 | 138 | The `server` lets us respond to HTTP requests in any way we like. We can use 139 | the `.mount_proc` method to attach a block of Ruby code to a particular request like this: 140 | 141 | ```ruby 142 | server.mount_proc("/home") do |request, response| 143 | puts("Hello server!") 144 | response.body = "Hello browser!" 145 | end 146 | ``` 147 | 148 | `.mount_proc` is a bit like `.times` from lesson 3: 149 | 150 | ```ruby 151 | 10.times do |i| 152 | puts("#{10 - i} green bottles, hanging on the wall,") 153 | # ... 154 | end 155 | ``` 156 | 157 | only instead of running the block 10 times straight away, WEBrick will run 158 | the block every time a request is made to the `/home` path. 159 | 160 | The final thing we need to do to make the server work is start it, which we 161 | do by calling the `.start` method after we've made all our calls to 162 | `.mount_proc`: 163 | 164 | ```ruby 165 | server.start 166 | ``` 167 | 168 | #### Task 5: Create a "hello world" server 169 | 170 | * Create a file inside the `lesson-4-ruby-on-the-web` folder called `hello-world-server.rb` 171 | * Copy / paste (or type) the following ruby into `hello-world-server.rb` 172 | 173 | ```ruby 174 | require("webrick") 175 | server = WEBrick::HTTPServer.new(Port: 8080, DocumentRoot: './public') 176 | 177 | server.mount_proc("/home") do |request, response| 178 | puts("Hello server!") 179 | response.body = "Hello browser!" 180 | end 181 | 182 | server.start 183 | ``` 184 | 185 | * On the command line, change directory into `lesson-4-ruby-on-the-web` using `cd` 186 | * Run `hello-world-server.rb` from the command line with `ruby hello-world-server.rb` 187 | * Visit [http://localhost:8080/home](http://localhost:8080/home) in your browser 188 | * Reload the page a few times to see what happens 189 | 190 |
191 | Answer 192 | 193 | You should see a web page that says "Hello browser!" and you should see some lines on the command line like this: 194 | 195 | ``` 196 | [2019-05-29 21:38:46] INFO WEBrick 1.3.1 197 | [2019-05-29 21:38:46] INFO ruby 2.3.7 (2018-03-28) [universal.x86_64-darwin17] 198 | [2019-05-29 21:38:46] INFO WEBrick::HTTPServer#start: pid=86541 port=8080 199 | Hello server! 200 | ::1 - - [29/May/2019:21:38:58 BST] "GET / HTTP/1.1" 200 14 201 | - -> / 202 | Hello server! 203 | ::1 - - [29/May/2019:21:38:59 BST] "GET /favicon.ico HTTP/1.1" 200 14 204 | http://localhost:8080/ -> /favicon.ico 205 | Hello server! 206 | ::1 - - [29/May/2019:21:39:03 BST] "GET / HTTP/1.1" 200 14 207 | - -> / 208 | Hello server! 209 | ::1 - - [29/May/2019:21:39:03 BST] "GET /favicon.ico HTTP/1.1" 200 14 210 | http://localhost:8080/ -> /favicon.ico 211 | ``` 212 | 213 | Note that `puts("Hello server!")` still prints to the command line, and that 214 | the `response.body` is what we see in the browser. 215 | 216 |
217 | 218 | ### Serving HTML 219 | 220 | We usually want to respond with some HTML, not just "Hello browser!". 221 | 222 | To make the browser treat our response as HTML we need to set an HTTP header 223 | called `Content-Type` like this: 224 | 225 | ```ruby 226 | server.mount_proc("/home") do |request, response| 227 | response.content_type = "text/html; charset=utf-8" 228 | response.body = "

Hello browser!

" 229 | end 230 | ``` 231 | 232 | It can get difficult to maintain if we put all our HTML in ruby strings like 233 | we did in the example above. It would be much nicer if we could have our HTML 234 | in html files and our Ruby in ruby files. Fortunately, we can achieve this 235 | with `File.read`: 236 | 237 | 238 | ```ruby 239 | server.mount_proc("/home") do |request, response| 240 | response.content_type = "text/html; charset=utf-8" 241 | response.body = File.read("index.html") 242 | end 243 | ``` 244 | 245 | (This assumes there's a file called `index.html` in your command line's working directory) 246 | 247 | #### Task 6: Serve an HTML file with WEBRick 248 | 249 | * Copy `lesson-1-html-and-css/index.html` into `lesson-4-ruby-on-the-web` 250 | * Create a copy of `hello-world-server.rb` called `barking-permit-server.rb` 251 | * Using the example above, make the server respond with the text from `index.html` 252 | * Run the server with `ruby barking-permit-server.rb` and visit [http://localhost:8080/home](http://localhost:8080/home) to check it works 253 | * When you're done, stop the server with `CTRL + C` 254 | 255 |
256 | Answer 257 | 258 | ```ruby 259 | require("webrick") 260 | server = WEBrick::HTTPServer.new(Port: 8080, DocumentRoot: './public') 261 | 262 | server.mount_proc("/home") do |request, response| 263 | response.body = File.read("index.html") 264 | end 265 | 266 | server.start 267 | ``` 268 | 269 |
270 | ### Responding to requests 271 | 272 | Our "Apply for a Barking Permit" page contains a form. 273 | 274 | Forms let the user provide the server with some input. When you submit the 275 | form you should see the URL update to have `?dog-name=Fido&dog-age=3` at the 276 | end. 277 | 278 | What's happening is the browser is making a second HTTP request to the 279 | server, but this time it's passing the user input in the URL (the bits after 280 | the question mark are called query parameters). 281 | 282 | We can access query parameters inside our WEBrick block using 283 | `request.query["key"]` (note: square brackets, not round brackets) 284 | 285 | ```ruby 286 | server.mount_proc("/home") do |request, response| 287 | 288 | dog_name = request.query["dog-name"] 289 | dog_age = request.query["dog-age"] 290 | 291 | puts("The dog #{dog_name} is #{dog_age} years old") 292 | 293 | response.body = File.read("index.html") 294 | end 295 | ``` 296 | 297 | #### Task 7: different responses depending on the query 298 | 299 | * Update `barking-permit-server.rb` to read user input with `request.query[]` 300 | * Using `if request.query["dog-name"]` set the value of `response.body` to be 301 | "The dog Fido is 3 years old" if the user provided a name, or 302 | `File.read(...)` if not 303 | * Run the server with `ruby barking-permit-server.rb`, visit [http://localhost:8080/home](http://localhost:8080/home) and submit the form 304 | * When you're done, stop the server with `CTRL + C` 305 | 306 |
307 | Answer 308 | 309 | ```ruby 310 | require("webrick") 311 | server = WEBrick::HTTPServer.new(Port: 8080, DocumentRoot: './public') 312 | 313 | server.mount_proc("/home") do |request, response| 314 | dog_name = request.query["dog-name"] 315 | dog_age = request.query["dog-age"] 316 | 317 | if dog_name 318 | response.body = "The dog #{dog_name} is #{dog_age} years old" 319 | else 320 | response.body = File.read("index.html") 321 | end 322 | end 323 | 324 | server.start 325 | ``` 326 | 327 |
328 | 329 | ### Templating HTML 330 | 331 | We've learned how to get the user's form input on the server, and change our 332 | response depending on the input. 333 | 334 | Our response to the user should be HTML as well though. If we're reading the 335 | HTML response from a file how do we change the contents based on the user's 336 | input? 337 | 338 | Templating lets us take a file and substitute placeholders with values of our 339 | choice. There are lots of fancy templating languages out there, but for us 340 | Ruby's `.sub` method will be good enough. 341 | 342 | Imagine we had some HTML in a file called `fruits.html`: 343 | 344 | ```html 345 |

Favourite Fruit

346 | 347 |

My favourite fruit is FAVOURITE_FRUIT_NAME. I like it the best because it is FAVOURITE_FRUIT_REASON.

348 | ``` 349 | 350 | We could load this file up, and then substitute the placeholders like this: 351 | 352 | ```ruby 353 | File.read("fruits.html") 354 | .sub("FAVOURITE_FRUIT_NAME", "Banana") 355 | .sub("FAVOURITE_FRUIT_REASON", "easy to peel") 356 | ``` 357 | 358 | Which would return: 359 | 360 | ```html 361 |

Favourite Fruit

362 | 363 |

My favourite fruit is Banana. I like it the best because it is easy to peel.

364 | ``` 365 | 366 | #### Task 8: Template barking permit 367 | 368 | Create a file called `barking-permit-template.html` in `lesson-4-ruby-on-the-web`. 369 | 370 | Add the following HTML to the file (it's fine to copy-paste this): 371 | 372 |
373 | HTML for `barking-permit-template.html` 374 | 375 | ```html 376 | 377 | 378 | 379 | Apply for a Barking Permit 380 | 381 | 392 | 393 | 394 |
395 |

Apply for a Barking Permit

396 |
397 |
398 |
399 |

400 | Application complete 401 |

402 |
403 | Your permit is available below 404 |
405 |
406 |
407 | 408 | 409 | 410 | 411 | 412 |
Barking Permit
A puppy in a hat
NameDOG_NAME
Age (human years)DOG_AGE_HUMAN_YEARS
413 |
414 |
415 |
416 |
417 | 418 | 419 | ``` 420 | 421 |
422 | 423 | Update `barking-permit-server.rb` so that when `request.query["dog-name"]` is 424 | set, `response.body` is set to `File.read("barking-permit-template.html")`. 425 | 426 | Use `.sub` to replace `DOG_NAME` with `request.query["dog-name"]` and a 427 | second `.sub` to replace `DOG_AGE_HUMAN_YEARS` with `request.query["dog-age"]`. 428 | 429 | Run the server with `ruby barking-permit-server.rb`, visit [http://localhost:8080/home](http://localhost:8080/home) and submit the form. 430 | 431 | When you're done, stop the server with `CTRL + C`. 432 | 433 |
434 | Answer 435 | 436 | ```ruby 437 | require("webrick") 438 | server = WEBrick::HTTPServer.new(Port: 8080, DocumentRoot: './public') 439 | 440 | server.mount_proc("/home") do |request, response| 441 | dog_name = request.query["dog-name"] 442 | dog_age = request.query["dog-age"] 443 | 444 | if dog_name 445 | response.body = File.read("barking-permit-template.html") 446 | .sub("DOG_NAME", dog_name) 447 | .sub("DOG_AGE_HUMAN_YEARS", dog_age) 448 | else 449 | response.body = File.read("index.html") 450 | end 451 | end 452 | 453 | server.start 454 | ``` 455 | 456 |
457 | 458 | ### Finishing off the Barking Permit 459 | 460 | Following Task 8, our Barking Permit has: 461 | 462 | * Name 463 | * Age (human years) 464 | 465 | We could use Ruby to add some more rows to the permit and make it a bit more 466 | useful. For example: age in Dog Years (from lesson 3) and how long the permit 467 | is valid for. 468 | 469 | #### Task 9: Add rows to the Barking Permit 470 | 471 | * Add rows (`...`) with template placeholders to `barking-permit-template.html` for: 472 | * Age (dog years) (`DOG_AGE_DOG_YEARS`) 473 | * Issued on (`PERMIT_ISSUED_ON`) 474 | * Valid until (`PERMIT_VALID_UNTIL`) 475 | * Calculate values for the placeholders using Ruby 476 | * Age (dog years) should be the Age in human years multiplied by 7 (as per lesson 3) 477 | * Issued on should be today's date, formatted as `Day/Month/Year` 478 | * Valid until should be today's date + 1,000 days (arbitrarily), formatted as `Day/Month/Year` 479 | * Use three more `.sub`s to replace the placeholders 480 | * Run the server with `ruby barking-permit-server.rb`, visit [http://localhost:8080/home](http://localhost:8080/home) and submit the form. 481 | * When you're done, stop the server with `CTRL + C`. 482 | 483 |
484 | Answer 485 | 486 | ```ruby 487 | require("webrick") 488 | require("date") 489 | 490 | def convert_to_dog_years(age_human_years) 491 | return age_human_years * 7 492 | end 493 | 494 | server = WEBrick::HTTPServer.new(Port: 8080, DocumentRoot: './public') 495 | 496 | server.mount_proc("/home") do |request, response| 497 | dog_name = request.query["dog-name"] 498 | dog_age = request.query["dog-age"] 499 | 500 | if dog_name 501 | response.body = File.read("barking-permit-template.html") 502 | .sub("DOG_NAME", dog_name) 503 | .sub("DOG_AGE_HUMAN_YEARS", dog_age) 504 | .sub("DOG_AGE_DOG_YEARS", convert_to_dog_years(dog_age.to_i).to_s) 505 | .sub("PERMIT_ISSUED_ON", Date.today.strftime("%d/%m/%Y")) 506 | .sub("PERMIT_VALID_UNTIL", (Date.today + 1000).strftime("%d/%m/%Y")) 507 | else 508 | response.body = File.read("index.html") 509 | end 510 | end 511 | 512 | server.start 513 | ``` 514 | 515 |
516 | 517 | ### Warning: security! 518 | 519 | We've deliberately cut some corners by using `.sub` for our templating 520 | which would cause security problems in a production application. 521 | 522 | In particular, mixing user input and HTML can leave us vulnerable to a thing 523 | called [Cross-site scripting](https://en.wikipedia.org/wiki/Cross-site_scripting). 524 | 525 | You do not need to worry about this for the purposes of this lesson, but if 526 | you're building a production website make sure to talk to a developer to 527 | check you're following good security practices. 528 | 529 | Frameworks like [Ruby on Rails](https://rubyonrails.org/) and 530 | [Sinatra](http://sinatrarb.com/) help you avoid making security mistakes like 531 | this. 532 | 533 | ## Congratulations! 534 | 535 | If you've made it this far, give yourself a massive pat on the back! These 536 | three lessons have been a whirlwind introduction to the world of programming 537 | on the web. Do not worry if it things still seem confusing - programming is a 538 | skill that takes time to learn. 539 | 540 | Programming is amazingly useful now that computers are such a big part of our 541 | lives, but it can also be great fun. Hopefully this is just the start of your 542 | learning journey! 543 | 544 | ## Further reading 545 | 546 | * [http://tutorials.codebar.io/](http://tutorials.codebar.io/) 547 | * [http://railsgirls.com/](http://railsgirls.com/) 548 | -------------------------------------------------------------------------------- /source/lesson-1-html-and-css.html.md.erb: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Lesson 1: HTML and CSS" 3 | weight: 3 4 | --- 5 | 6 | # Lesson 1: HTML and CSS 7 | 8 | ## Introduction 9 | 10 | ### Objectives 11 | 12 | In this tutorial we are going to look at: 13 | 14 | * what is HTML? 15 | * what is an element? 16 | * webpage structure 17 | * fundamental HTML elements 18 | * applying styles with classes and CSS 19 | 20 | ### Goal 21 | 22 | By the end of this tutorial you will have built an "Apply for a barking permit" webpage: 23 | 24 |
25 | Apply for a Barking Permit website, showing an image, a paragraph of text, a link and a form 26 | 27 |
28 | 29 | This webpage contains a heading, some body text, two forms and a button. 30 | 31 | Even though HTML and CSS are not programming languages they’re important fundamentals, and they’ll help you understand how the internet works. 32 | 33 | We’ll cover programming languages (like Ruby and Python) in future lessons. 34 | 35 | ## Introduction to HTML and CSS 36 | 37 | ### What do HTML and CSS stand for? 38 | 39 | HTML stands for Hyper Text Markup Language 40 | 41 | CSS stands for Cascading Style Sheets 42 | 43 | ### What are HTML and CSS? 44 | 45 | HTML is the language used to build websites. All text and content that you 46 | see on the internet is built using HTML. 47 | 48 | CSS is used with HTML to style the page. 49 | 50 | Whenever you go to a website (e.g. www.gov.uk) your browser sends a request 51 | to a special computer called a "server". The server sends back HTML and CSS, 52 | which your browser turns into a webpage for you to look at. 53 | 54 | ## HTML elements 55 | 56 | An element is an HTML building block. There are paragraphs, headings, 57 | links, lists, and many more. 58 | 59 | HTML elements are made up of an opening tag (sometimes including some attributes), content, and a closing tag. 60 | 61 | ![Diagram showing the structure of an HTML element](images/lesson-1/image7.png) 62 | (Image from wikipedia) 63 | 64 | See the [Mozilla HTML elements reference documentation](https://developer.mozilla.org/en/docs/Web/HTML/Element) for more information. 65 | 66 | ## Webpage structure 67 | 68 | ### `doctype` and `HTML` 69 | 70 | The doctype is the first thing that must be defined in an HTML page. It tells 71 | the browser which version of HTML the page is using. 72 | 73 | ```html 74 | 75 | ``` 76 | 77 | These days you will only ever need to use `html`. There used to be lots of 78 | complicated doctypes in the olden days. See the [W3C documentation on doctypes and markup styles](https://www.w3.org/wiki/Doctypes_and_markup_styles) for more information. 79 | 80 | The doctype is always followed by the `` tag, which contains the contents of your page. 81 | 82 | ```html 83 | 84 | 85 | 86 | ``` 87 | 88 | ### `head` and `body` tags 89 | 90 | A HTML page is split into two parts. The `head` and the `body`. 91 | 92 | The `head` contains webpage information like the page title (the text in the 93 | browser tab), stylesheets, scripts and other information about the page. 94 | Everything in the `head` is invisible - you can’t put an image or a paragraph 95 | of text in `head`. 96 | 97 | The `body` contains webpage content that is visible to the user. 98 | 99 | ## Presentational HTML Elements 100 | 101 | Let's start by defining the basic structure of your website. 102 | 103 | Open Visual Studio Code and create a new folder for your work called `lesson-1-html-and-css`. Select **File > Open Folder...** and select the correct folder: 104 | 105 |
106 | Screenshots showing how to add a folder in Visual Studio Code 107 | Screenshot showing how to add a folder to Visual Studio Code. Menu > File > Add Project Folder... 108 | Screenshot showing how to create a new folder in the Add Project Folder dialog 109 |
110 | 111 | Then inside this folder create a new file called `index.html` by clicking the **New File...* button in the sidebar: 112 | 113 |
114 | Screenshot showing how to add a file in Visual Studio Code 115 | Screenshot showing how to add a file in Visual Studio Code. Right-click the folder in the sidebar, then select 'New File'. 116 |
117 | 118 | ### Task 1: doctype, html, head and body 119 | 120 | Using what we just learnt, and with guidance from your coach, do the following: 121 | 122 | * declare the doctype to be HTML 123 | * open and close a set of `` tags 124 | * Within this, create the `head` and `body` tags 125 | 126 | Once you've done this, open `index.html` in your web browser: 127 | 128 |
129 | Screenshot showing how to open the HTML file in Google Chrome: 130 | Screenshot showing how to open the HTML file in Google Chrome 131 |
132 | 133 | Do you see anything on the page? 134 | 135 | ### Task 2: set the page title 136 | 137 | Now inside your head tag create a `` tag with `Apply for a Barking Permit` as your title. 138 | 139 | You should see that the title of the tab in your browser has changed. If not, double check your code. 140 | 141 | ```html 142 | <!doctype html> 143 | <html> 144 | <head> 145 | <title>Apply for a Barking Permit 146 | 147 | 148 | 149 | 150 | ``` 151 | 152 | Notice how in our example each tag is indented to its parent tag. It’s not required 153 | but it makes your code much more readable and you’ll be able to see nested tags more easily. 154 | 155 | In HTML multiple spaces and newlines all get squished down into one space. 156 | 157 | ``` 158 | You can 159 | write 160 | 161 | text like this 162 | ``` 163 | 164 | and they’ll end up getting displayed with all the space squished, like so: 165 | 166 | ``` 167 | You can write text like this 168 | ``` 169 | 170 | ### Element: heading (`h1`) 171 | 172 | Headings come in 6 levels: 173 | 174 | ```html 175 |

Heading

176 |

Heading

177 |

Heading

178 |

Heading

179 |
Heading
180 |
Heading
181 | ``` 182 | 183 | A `h1` defines the most important heading whereas a `h6` defines the least important. 184 | 185 | Headings should go from `h1` to `h6` in order - always start from `

`, next use `

`, and so on. 186 | 187 | It's important to not skip one or more heading levels - this is because screenreaders can jump from heading to heading and leaving a heading level out may lead to a user being confused. 188 | 189 | 190 | Don't: 191 | 192 | ```html 193 |

Heading 1

194 |

Heading 3

195 |

Heading 4

196 | ``` 197 | 198 | Do: 199 | 200 | ```html 201 |

Heading 1

202 |

Heading 2

203 |

Another heading 2

204 |

Yet another heading 2

205 |

Heading 3

206 | ``` 207 | 208 | Headings can skip a level when going back up to a more important heading level: 209 | 210 | ```html 211 |

Heading 1

212 |

Heading 2

213 |

Heading 3

214 |

Heading 4

215 |

Another heading 2

216 |

Another heading 3

217 | ``` 218 | 219 | #### Task 3: add a heading 220 | 221 | Add a `h1` heading tag, which includes the phrase `Apply for a Barking Permit`, inside the `body` tag of your page. 222 | 223 | ### Element: paragraph (`p`) 224 | 225 | Putting content into a `

` tag will break your text up into paragraphs. 226 | This helps make the content of your page easier to read for the user. 227 | 228 | #### Task 4: add a paragraph 229 | 230 | Add the following paragraph inside your `` tag, after the `

`: 231 | 232 | ```html 233 |

234 | The ministry of dogs is trying a new pilot. Good dogs can apply for a 235 | barking permit so they can woof whenever they like. It’s not yet clear how 236 | this permit will be enforced. 237 |

238 | ``` 239 | 240 | ### Element: link (`a`) 241 | 242 | A link lets the user go to another webpage. We use the attribute `href` to indicate where you want the user to go. 243 | 244 | The link tag is called `a` for "anchor". 245 | 246 | #### Task 5: add a link 247 | 248 | Add a link to the end of your paragraph: 249 | 250 | ```html 251 | 252 | More information about barking 253 | 254 | ``` 255 | 256 | ### Element: div (`div`) 257 | 258 | A div tag lets you group elements together. Grouping elements is useful as we can later style them together (e.g. giving them all the same colour). 259 | 260 | #### Task 6: add a div 261 | 262 | Wrap your existing paragraph, link and heading in a div: 263 | 264 | ```html 265 |
266 |

Apply for a Barking Permit

267 |

268 | The ministry of dogs is trying a new pilot. Good dogs can apply for a barking permit so they can woof whenever and wherever they like. It’s not yet clear how this permit will be enforced. 269 | More information about barking. 270 |

271 |
272 | ``` 273 | 274 | It's called "div" for "division". 275 | 276 | ### Element: image (`img`) 277 | 278 | So far we've learned a lot about how to add text to our page. Now let’s add some images! 279 | 280 | Before we start, we'll need to add the image files we want to use to the 281 | project folder. 282 | 283 | It's common to keep images in their own folder, so first, 284 | create a folder called `images` inside the same folder as your HTML file. 285 | 286 | Next, download the images you'll need. Do this by right-clicking each of 287 | the following links, select 'Save Link As...', and save it to the images folder 288 | you just created: 289 | 290 | * Shiba Inu 291 | * puppy in a hat 292 | 293 | Images are primarily made up of three components: 294 | 295 | * the `` tag 296 | * the `src` attribute, which gives the location, or source, of the image 297 | * the `alt` attribute, which is displayed if the image can't be shown, and is read by screen reader software 298 | 299 | In order for us to see this image on the webpage we need to link to the 300 | image, this involves telling the webpage where it is and what it is called. 301 | 302 | #### Task 7: add an image 303 | 304 | After the main heading of the page, add the following: 305 | 306 | ```html 307 | A happy shiba inu 308 | ``` 309 | 310 | Here you can see we have told the `src` of the image to look in the images 311 | folder and display the image `shiba-inu.jpeg`, then we have given it a 312 | description in the `alt` attribute. 313 | 314 | ## Forms 315 | 316 | Forms let you ask your user for input. There are a number of interactive 317 | components (like text boxes and buttons) you can use in forms. 318 | 319 | ### Element: form (`form`) 320 | 321 | The `
` element groups a set of components together so all of the inputs 322 | can be submitted at once. 323 | 324 | #### Task 8: create an empty form 325 | 326 | Create an empty form at the end your `
`: 327 | 328 | ```html 329 | ... 330 | 331 | 332 |
333 | 334 | ``` 335 | 336 | 337 | ### Elements: label (`label`) and input (`input`) 338 | 339 | Labels and Inputs work together to tell the user what information they need to provide and to let them enter it. 340 | 341 | `