03-02-2022

812 words 5 minutes

Meta Stuff

Sort out bspwm desktops - gah! Zoom and slack are driving me insane, and I'm almost there -


Today's Foci

Focus 1

  1. Understand how Ruby classes work through Sinatra/web-frameworks
  2. Access classes and use them via the web-framework

Focus 2

  1. Clarify MVC
  2. Detailed explanation of MVC model?

Debugging the Web

Debugging steps

  • Tighten the loop
  • Get visibility

Follow the Flow

p output the model and controller variables where relevant

check test against view

run app

FILENAME && LINE

p params!

I managed to explain something in the workshop - I wound about a little, but apparently it helped a small number of people - so that's a small win for today.


Remember HTML FORMS

  • method = post
  • action = send post to url /some/url

Using Sinatra, the variable needs to be sent in via an instance variable


Right, before lunch, I'm gonna study the workshop code we looked at. It seems to implement selenium and RSpec and Capybara together in a clear, concise fashion. ( apart from the kword subject! agh! )

Flying Solo

huh - I'm working solo today. What do I do?

I didn't get too deep into the selenium/RS/Capybara understanding and file format - so I'm gonna look into that somewhat.

But first I need to debug this thing!

OOOO, I didn't need to use the

.to not_include

syntax

I only needed

.to_not include

whoops!

So in continue to debug this error, I have p'd everything out - it looks like its in the right place so why isn't it working?

time for internet dev tools!

Huh - the app itself appears to be working as intended.

...

some time later

Huzzah! We got there.

How did I get there.

I couldn't see anything was wrong immediately - it appears to function on the surface. Even the app works properly by using the tags ( at least when I used it )

So how did I solve this?

I followed the flow, explicitly, and p'd out every related variable I could find.

As I was doing this, I kept wondering why the array was empty? If it works, it shouldn't be empty! But it wasnt the PostManager.(private)array I was looking for.

It returns the post's array attribute, stored in the post's 'tags' instance variable

some_post = (title="Coffee in C18", content="Clever things", tags = ["coffee", "clever"])

the code was returning post.title - so the array is empty

That in itself is interesting because of Ruby being made in C where C strings are character-arrays with an end token '0/'.

I'm supposing this is because Ruby turns almost everything into an object?

solution

class PostManager
  def self.instance
    @instance ||= self.new
  end

  def initialize
    @posts = []
  end

  def add_post(post)
    @posts << post
  end

  def all_posts
    @posts
  end

  def all_posts_by_tag(tag)
    p '===== tag ====='
    p tag
    @posts.select do |post|
      p '===== post ====='
      p post
      p '===== post title ====='
      p post.title
      p '===== post tags(s) ====='
      p post.tags
	  # previously, post.title.include?(tag)
      post.tags.include?(tag)
    end
  end
end

Pairing Challenge Solo

Right - I'm going to continue with the pairing challenge - or maybe even start again - hmm.

Yeah. I'm gonna try that!

First, the user stories

As two Players,
So we can play a personalised game of Battle,
We want to Start a fight by entering our Names and seeing them
As Player 1,
So I can see how close I am to winning
I want to see Player 2's Hit Points
As Player 1,
So I can win a game of Battle,
I want to attack Player 2, and I want to get a confirmation
As Player 1,
So I can start to win a game of Battle,
I want my attack to reduce Player 2's HP by 10
As two Players,
So we can continue our game of Battle,
We want to switch turns
As Player 1,
So I can see how close I am to losing,
I want to see my own hit points
As Player 1,
So I can lose a game of Battle,
I want Player 2 to attack me, and I want to get a confirmation
As Player 1,
So I can start to lose a game of Battle,
I want Player 2's attack to reduce my HP by 10
As a Player,
So I can Lose a game of Battle,
I want to see a 'Lose' message if I reach 0HP first
As a Player,
So I can play a suspenseful game of Battle,
I want all Attacks to deal a random amount of damage
As a lonely Player,
So I can keep my Battle skills up to scratch
I want to play a Computerised opponent
As a Player,
So I can enjoy a game of Battle with more variety,
I want to choose from a range of attacks I could make
As a Player,
So I can better enjoy a game of Battle,
I want some of my attacks to Paralyse an opponent (chance of losing their next attack)
As a Player,
So I can better enjoy a game of Battle,
I want one of my attacks to have a chance of Poisoning my Opponent (Opponent takes a small random amount of damage at the beginning of their turn)
As a Player,
So I can better enjoy a game of Battle,
I want to make an attack that has a chance of sending my Opponent to Sleep (Opponent definitely misses next turn)
As a Player,
So I can extend my joyous experience of Battle,
I want to have an attack that heals some of my Hit Points
As a Player,
So I can enjoy my game of Battle,
I want a sexy user interface

Diagram Modelling - OOP

NounVerbProp?
Gamestart
show_health
change_turn
lose_game
win_game
Playername
health
attack
confirm_hit
confirm_struck
paralyze
posion
sleep
heal
Computername
health
attack
UI
NounProperty or Owner?
ActionsOwned by
ActionsProperty it Reads or Changes
ClassCLASSNAME
Properties (instance variables)
Actions (methods)

Looks like I need to look into class Aggregation Composition and Association

  • Aggregates exist independently - they're mutually exclusive

    • Two People can exist independent of one another
    • Aggregation doesn;t link state together
    • Nor is there a parent-child relationship
  • Composition imples strong dependency - they're mutually inclusive A person cannot exist without a head, or torso

  • Reflexive Association

    • Fruit class, and Mango instance, and Apple instance - the Mango and Apple are implicitly linked because they're both a little fruity
  • Directed Association

    • direction of flow within classes
    • a server passes information to a client
  • Composite Aggregation

    • a two way relationship between objects
    • a whole/part relationship
    • If the composite is deleted, all subsiduary parts are deleted also
    • In a windowing system, a frame belongs to a window
  • Aggregation relationship

    • an object of one class can access or own an object of another class
    • a car needs a wheel - but a wheel doesn't need a car

Right, I've had a crack at a UML diagram for the above Classes of Game, Player, and even Computer - I'll see if I can get it into this page later. It even saves as an SVG by default!


Walkthrough!

I haven't learned TDD in web yet - properly - and I think this walkthrough will show me some of that. I'm going through the walkthrough and then rebuilding it in my fashion. That seems to make sense to me.

Create a Modular Sinatra app using rackup

setup the RSpec environment something like

ENV['RACK_ENV'] = 'test'

# require our Sinatra app file
require File.join(File.dirname(__FILE__), '..', 'app.rb')

require 'capybara'
require 'capybara/rspec'
require 'rspec'

# tell Capybara about our app class
Capybara.app = SomeApp

set up a ./spec/features directory for the capybara testing

with capybara, use

feature 'with this feature' do
  scenario 'do this thing' do
    DO THE THING ( LOGIC )
  end
end

When testing capybara:

What does the User do?

What does the User see?

use post when changing the server state

use capybara

don't render directly from POST

POST/redirect/GET

POST '/some/route'
...
LOGIC FOR DATA
...
redirect '/some/other/route'
GET 'some/other/route'
...
LOGIC / VIEW
...

To store short-term data on a server, use a session. Store the name of a used across multiple requests

save_and_open_page # saves and opens a browser to display the page