How i can validate attr in Ruby - ruby

How I can validate attr in Ruby?
My file airplane.rb
class Airplane
include Validatable
attr_reader :aircraft_type, :weight
attr_accessor :speed, :altitude, :course
def initialize(aircraft_type, options={})
#aircraft_type = aircraft_type.to_s
#course = options[:course] || random_course
#weight = options[:weight] || rand(1...1000)
#speed = options[:speed] || rand(1...500)
#apltitude = options[:apltitude] || rand(50...3000)
#position_x = options[:position_x] || rand(1...3000)
#position_y = options[:position_y] || rand(1...3000)
check_course
end
def position
#position = [#position_x, #position_y]
end
def check_course
if #course < 1
#course = 1
puts "Invalid course. Set min"
elsif #course > 360
#course = 360
puts "Invalid course. Set max"
else
#course = #course
end
end
def random_course
#course = rand(1..360)
end
end
My file validatable.rb where all values ​​must be checked
module Validatable
##validations={}
# I need receive = {presence: [:weight, :length], aircraft_type: [:length]}
def self.validates_presence_of(*attrs)
##validations[:presence] = attrs
end
def validate
##validations.each do |v, fields|
fields.each {|field_name| self.send("validate_#{v}_of", field_name)}
end
end
private
def validate_presence_of(field_name)
end
end
My file init.rb with airplanes attr
airplane1 = Airplane.new("Boeing 74", course: 600, speed: 300, apltitude: 300)
airplane2 = Airplane.new("Boeing 700", course: 250, speed: 300, apltitude: 300)
airplane3 = BigAirplane.new("Boeing 707", weight: 50, speed: 300, apltitude: 400)
How I can finish validatable.rb to validate each value in each airplane?

Use ActiveModel::Validations instead of re-inventing the wheel.
Refer:
http://yehudakatz.com/2010/01/10/activemodel-make-any-ruby-object-feel-like-activerecord/
and
http://www.rubyinside.com/rails-3-0s-activemodel-how-to-give-ruby-classes-some-activerecord-magic-2937.html
and
http://asciicasts.com/episodes/211-validations-in-rails-3
Good luck.

Related

How can I jump on Gosu gem from Ruby?

I'm trying to recreate a simple game but I'm stuck at the moment that I'm trying to make jump my character( or player).
I've been checking the example from gosu but it's not really clear for me.
Can someone help me?
Here is my window code:
class Game < Gosu::Window
def initialize(background,player)
super 640,480
self.caption = "My First Game!"
#background = background
#player = player
#player.warp(170,352)
#x_back = #y_back = 0
#allow_to_press = true
end
# ...
def update
#...
if Gosu.button_down? Gosu::KbSpace and #allow_to_press
#allow_to_press = false
#player.jump
end
end
end
Then my player class:
class Player
def initialize(image)
#image = image
#x = #y = #vel_x = #vel_y = #angle = 0.0
#score = 0
end
def warp(x,y)
#x,#y = x,y
end
def draw
#image.draw_rot(#x,#y,1,#angle,0.5,0.5,0.3,0.3)
end
def jump
##y -= 15 # THIS IS NOT CORRECT
end
end
Basically, the idea is when u press Space, then the jump method is invoked and here i should be able to recreate an animation to move the "y" position up ( for example 15 px) and then go down again.
Just i have on my mind change the value of #y variable but i don't know how to do it with an animation and then come back at the original point.
Thanks!
Finally I got it!
What I did is split the jump and an update method inside player:
class Player
def initialize(image)
#image = image
#x = #y = #angle = 0.0
#score = #vel_y = #down_y = 0
#allow = true
end
def warp(x,y)
#x,#y = x,y
end
def update(jump_max)
#Jump UP
if #vel_y > 0
#allow = false
#vel_y.times do
#y-=0.5
end
#vel_y-=1
end
#Jump DOWN
if #vel_y < 0
(#vel_y*-1).times do
#y+=0.5
end
#vel_y+=1
end
check_jump
end
def draw
#image.draw_rot(#x,#y,1,#angle,0.5,0.5,0.3,0.3)
end
def jump(original)
#vel_y = original
#down_y = original * -1
end
def check_jump
if #vel_y == 0 and #allow == false
#vel_y = #down_y
#down_y = 0
#allow = true
end
end
end
And then on my Game class
...
def initialize(background,player,enemy_picture)
#size of the game
super 640,480
#original_y = 352
#original_x = 170
self.caption = "Le Wagon Game!"
#background = background
#player = player
#player.warp(#original_x,#original_y)
#enemy_anim = enemy_picture
#enemy = Array.new
#Scrolling effect
#x_back = #y_back = 0
#jump = true
#jumpy = 25
end
def update
if Gosu.button_down? Gosu::KbSpace and #jump
#jump = false
#player.jump(#jumpy)
end
#player.update(#jumpy)
end
def button_up(id)
if id == Gosu::KbSpace
#jump = true
end
super
end
end
So now I can press Space and it goes up, after finish the transition, it goes down

attr_accessor - Accessing an objects attributes from another class

I want to access the ogre's object's swings attribute from the Human's class. However, all I am getting is:
NameError: undefined local variable or method ogre for
**<Human:0x007fdb452fb4f8 #encounters=3, #saw_ogre=true>
Most likely a simple solution, and my brain is just not operating this morning. I am running tests with minitest. The test and classes are below:
ogre_test.rb
def test_it_swings_the_club_when_the_human_notices_it
ogre = Ogre.new('Brak')
human = Human.new
ogre.encounter(human)
assert_equal 0, ogre.swings
refute human.notices_ogre?
ogre.encounter(human)
ogre.encounter(human)
assert_equal 1, ogre.swings
assert human.notices_ogre?
end
ogre.rb
class Ogre
attr_accessor :swings
def initialize(name, home='Swamp')
#name = name
#home = home
#encounters = 0
#swings = 0
end
def name
#name
end
def home
#home
end
def encounter(human)
human.encounters
end
def encounter_counter
#encounters
end
def swing_at(human)
#swings += 1
end
def swings
#swings
end
end
class Human
def initialize(encounters=0)
#encounters = encounters
#saw_ogre = false
end
def name
"Jane"
end
def encounters
#encounters += 1
if #encounters % 3 == 0 and #encounters != 0
#saw_ogre = true
else
#saw_ogre = false
end
if #saw_ogre == true
ogre.swings += 1 # <----issue
end
end
def encounter_counter
#encounters
end
def notices_ogre?
#saw_ogre
end
end
The easy fix would be to pass the ogre object as an argument to encounters - assuming encounters isn't used anywhere else without the argument.
class Ogre
...
def encounter(human)
human.encounters(self)
end
...
end
class Human
...
def encounters(ogre)
#encounters += 1
if #encounters % 3 == 0 and #encounters != 0
#saw_ogre = true
else
#saw_ogre = false
end
if #saw_ogre == true
ogre.swings += 1 # <----issue
end
end
...
end

/usr/local/lib/ruby/gems/2.2.0/gems/gosu-0.10.4/lib/gosu/patches.rb:37:in `initialize': Cannot open file ./media/image.jpg (RuntimeError) in gosu

I have this code which is not giving the desired output and shows the above error.
require 'gosu'
def media_path(file)
File.join(File.dirname(File.dirname(
__FILE__)),'media', file)
end
#def media_path(file); File.expand_path "media/#{file}", File.dirname(__FILE__)
# end
class Explosion
FRAME_DELAY = 10 # ms
SPRITE = media_path('space.png')
def self.load_animation(window)
Gosu::Image.load_tiles(
window, SPRITE, 128, 128, false)
end
def initialize(animation, x, y)
#animation = animation
#x, #y = x, y
#current_frame = 0
end
def update
#current_frame += 1 if frame_expired?
end
def draw
return if done?
image = current_frame
image.draw(
#x - image.width / 2.0,
#y - image.height / 2.0,
0)
end
def done?
#done ||= #current_frame == #animation.size
end
private
def current_frame
#animation[#current_frame % #animation.size]
end
def frame_expired?
now = Gosu.milliseconds
#last_frame ||= now
if (now - #last_frame) > FRAME_DELAY
#last_frame = now
end
end
end
class GameWindow < Gosu::Window
BACKGROUND = media_path('image.jpg')
def initialize(width=800, height=600, fullscreen=false)
super
self.caption = 'Hello Animation'
#background = Gosu::Image.new(
self, BACKGROUND, false)
#animation = Explosion.load_animation(self)
#explosions = []
end
def update
#explosions.reject!(&:done?)
#explosions.map(&:update)
end
def button_down(id)
close if id == Gosu::KbEscape
if id == Gosu::MsLeft
#explosions.push(
Explosion.new(
#animation, mouse_x, mouse_y))
end
end
def needs_cursor?
true
end
def needs_redraw?
!#scene_ready || #explosions.any?
end
def draw
#scene_ready ||= true
#background.draw(0, 0, 0)
#explosions.map(&:draw)
end
end
window = GameWindow.new
window.show
It can't find ./media/image.jpg are you sure it is there, and can be opened, and is the current directory "." what you think it is?

Modeling a cookie with object composition in Ruby

I'm a new Rubyist and am wondering how I can access the ingredients class from individual cookies? As we all know, cookies are made of different ingredients. How can I specify default ingredients for individual cookies without setting default values? Even if I had default values, how would I update those to reflect the most current "recipe"? Please and thanks!
#Cookie Factory
module CookieFactory
def self.create(args)
cookie_batch = []
args.each do |cookie|
cookie_batch << PeanutButter.new if cookie == "peanut butter"
cookie_batch << ChocholateChip.new if cookie == "chocolate chip"
cookie_batch << Sugar.new if cookie == "sugar"
end
return cookie_batch
end
end
#Classes/Subclasses
class Ingredients
attr_reader
def initialize(contents = {})
# contents = defaults.merge(contents)
#sugar = contents.fetch(:sugar, "1.5 cups")
#salt = contents.fetch(:salt, "1 teaspoon")
#gluten = contents.fetch(:gluten, "0")
#cinnamon = contents.fetch(:cinnamon, "0.5 teaspoon")
end
end
class Cookie
attr_reader :status, :ingredients
def initialize(ingredients = {})
#ingredients = ingredients
#status = :doughy
super()
end
def bake!
#status = :baked
end
end
class PeanutButter < Cookie
attr_reader :peanut_count
def initialize
#peanut_count = 100
super()
end
def defaults
{
:peanut_shells => 5
}
end
end
class Sugar < Cookie
attr_reader :sugar
def initialize
#sugar = "1_cup"
super()
end
end
class ChocholateChip < Cookie
attr_reader :choc_chip_count
def initialize
#choc_chip_count = 200
super()
end
end
You can use Hash#merge to acheive this behavior:
class PeanutButter < Cookie
attr_reader :peanut_count
def initialize(ingredients)
#peanut_count = 100
super(ingredients.merge(defaults))
end
def defaults
{
:peanut_shells => 5
}
end
end

Min & max values for initialize hash

class Airplane
attr_reader :weight, :aircraft_type
attr_accessor :speed, :altitude, :course
def initialize(aircraft_type, options = {})
#aircraft_type = aircraft_type.to_s
#course = options[:course.to_s + "%"] || rand(1...360).to_s + "%"
end
How I can use minimum and maximum allowable values ​​for the hash in initialize from 1 to 360?
Example:
airplane1 = Airplane.new("Boeing 74", course: 200)
p radar1.airplanes
=> [#<Airplane:0x000000023dfc78 #aircraft_type="Boeing 74", #course="200%"]
But if I set to course value 370, airplane1 should not work
This could be refactored i'm sure but this is what i came up with
class Plane
attr_reader :weight, :aircraft_type
attr_accessor :speed, :altitude, :course
def initialize(aircraft_type, options = {})
#aircraft_type = aircraft_type.to_s
#course = options[:course] || random_course
check_course
end
def check_course
if #course < 1 or #course > 360
#course = 1
puts "Invalid course. Set min"
elsif #course > 360
#course = 360
puts "Invalid course. Set max"
else
#course = #course
end
end
def random_course
#course = rand(1..360)
end
end
course is an angle, isn't it? shouldn't it be 0...360 the valid range for it? and why the final "%"? and why work with a string instead of an integer?
Anyway, that's what I'd write:
#course = ((options[:course] || rand(360)) % 360).to_s + "%"
I think you mean you don't want to let people pass in something like {course: '9000%'} for options and you want to error out if it's invalid. If that's the case, you can just test if it's in range:
def initialize(aircraft_type, options = {})
#aircraft_type = aircraft_type.to_s
allowed_range = 1...360
passed_course = options[:course]
#course = case passed_course
when nil
"#{rand allowed_range}%"
when allowed_range
"#{passed_course}%"
else
raise ArgumentError, "Invalid course: #{passed_course}"
end
end

Resources