Organize my array ruby - ruby

im trying to optimize my code as much as possible and i've reached a dead end.
my code looks like this:
class Person
attr_accessor :age
def initialize(age)
#age = age
end
end
people = [Person.new(10), Person.new(20), Person.new(30)]
newperson1 = [Person.new(10)]
newperson2 = [Person.new(20)]
newperson3 = [Person.new(30)]
Is there a way where i can get ruby to automatically pull data out from the people array and name them as following newperson1 and so on..
Best regards

That is definitely a code smell. You should refer to them as [people[0]], [people[1]], ... .
But if you insist on doing so, and if you can wait until December 25 (Ruby 2.1), then you can do:
people.each.with_index(1) do |person, i|
binding.local_variable_set("newperson#{i}", [person])
end

I think this is what you're trying to do...
newperson1 = people[0]
puts newperson1.age
The output of this 10 as expected.

Related

Ruby OOP - Instance Method

Ruby OOP beginner here. Trying to build a simple Vending machine code.
class VendingMachine
# TODO: add relevant getter/setter to this class to make the scenarios work properly.
attr_reader :snack_price_cents, :user_balance_cents
attr_accessor :snack_count
def initialize(snack_price_cents, snack_count)
#user_balance_cents = 0
#snack_count = snack_count
#snack_price_cents = snack_price_cents
end
def insert_coin(input_cents)
#user_balance_cents = user_balance_cents + input_cents if input_cents
end
def buy_snack
if snack_count.zero? || user_balance_cents.zero?
#snack_count = snack_count
else
#snack_count = snack_count - 1
#user_balance_cents = user_balance_cents - snack_price_cents
end
end
end
I am trying to understand what happens to snack_count, user_balance_cents and snack_price_cents when the user pushes a button to buy a snack?
It seems like all is working okay except for the user_balance_cents but I am getting:
should not let you buy a snack if you didn't insert enough money (error path) (FAILED - 1)"
error. Any help?
I would guess that your error here is that you are checking that user_balance_cents is not zero, but you are not checking that it as least snack_price_cents.
i.e. if I put 10c in and try to buy a 50c snack, it will give me it.

Refactor the Ruby CLI program

I'm new to programming in Ruby.
How do I make the output show Revenue and Profit or Loss?
How can I refactor the following code to look neater? I know it's wrong but I have no idea how to take my if profit out of the initialize method.
class Theater
attr_accessor :ticket_price, :number_of_attendees, :revenue, :cost
def initialize
puts "What is your selling price of the ticket?"
#ticket_price = gets.chomp.to_i
puts "How many audience are there?"
#number_of_attendees = gets.chomp.to_i
#revenue = (#number_of_attendees * #ticket_price)
#cost = (#number_of_attendees * 3) + 180
#profit = (#revenue - #cost)
if #profit > 0
puts "Profit made: $#{#profit}"
else
puts "Loss incurred: $#{#profit.abs}"
end
end
end
theater = Theater.new
# theater.profit
# puts "Revenue for the theater is RM#{theater.revenue}."
# I hope to put my Profit/Loss here
#
# puts theater.revenue
Thanks guys.
Do not initialize the object with input from the user, make your object accept the needed values. Make a method to read the needed input and return you new Theater. Last of all put the if in separate method like #report_profit.
Remember constructors are for setting up the initial state of the object, making sure it is in a valid state. The constructor should not have side effects(in your case system input/output). This is something to be aware for all programming languages, not just ruby.
Try this:
class Theatre
COST = { running: 3, fixed: 180 }
attr_accessor :number_of_audience, :ticket_price
def revenue
#number_of_audience * #ticket_price
end
def total_cost
COST[:fixed] + (#number_of_audience * COST[:running])
end
def net
revenue - total_cost
end
def profit?
net > 0
end
end
class TheatreCLI
def initialize
#theatre = Theatre.new
end
def seek_number_of_attendes
print 'Number of audience: '
#theatre.number_of_audience = gets.chomp.to_i
end
def seek_ticket_price
print 'Ticket price: '
#theatre.ticket_price = gets.chomp.to_i
end
def print_revenue
puts "Revenue for the theatre is RM #{#theatre.revenue}."
end
def print_profit
message_prefix = #theatre.profit? ? 'Profit made' : 'Loss incurred'
puts "#{message_prefix} #{#theatre.net.abs}."
end
def self.run
TheatreCLI.new.instance_eval do
seek_ticket_price
seek_number_of_attendes
print_revenue
print_profit
end
end
end
TheatreCLI.run
Notes:
Never use your constructor (initialize method) for anything other than initial setup.
Try to keep all methods under 5 lines.
Always try to keep each class handle a single responsibility; for instance, printing and formatting output is not something the Theatre class needs to care.
Try extracting all hard coded values; eg see the COST hash.
Use apt variables consistent to the domain. Eg: net instead of profit makes the intent clear.

How to list the description of all Revision within a Task?

Trying to print out Description of all Revisions within a task for a given set of tasks. But RevisionHistory seems to be a HashArray and not a RallyObject. Not sure how to proceed. Any help here would be appreciated. Here is a snippet of the direction I am taking. What should I replace the ------ with?
results.each do |task|
#revisions = task.rally_object['RevisionHistory'].-------
#revisions.each do |task_revision|
puts task_revision["Description"]
end
end
you shouldn't need to get at the RallyObject there, instead that class was meant to have convenience methods via method missing or [FieldName] to get at the fields for each object. For example try your loop as:
results.each do |task|
#revisions = task['RevisionHistory']['Revisions']
#you may need a #revisions = task['RevisionHistory'].read or something like that depending what you fetched in your query.
#revisions.each do |task_revision|
puts task_revision["Description"]
end
end
Hope that helps.

Mapping XML to Ruby objects

I want to communicate between ruby and other applications in XML. I have defined a schema for this communication and I'm looking for the best way to do the transformation from data in Ruby to the XML and vice versa.
I have an XML document my_document.xml:
<myDocument>
<number>1</number>
<distance units="km">20</distance>
</myDocument>
Which conforms to an Schema my_document_type.xsd (I shalln't bother writing it out here).
Now I'd like to have the following class automatically generated from the XSD - is this reasonable or feasible?
# Represents a document created in the form of my_document_type.xsd
class MyDocument
attr_accessor :number, :distance, :distance_units
# Allows me to create this object from data in Ruby
def initialize(data)
#number = data['number']
#distance = data['distance']
#distance_units = data['distance_units']
end
# Takes an XML document of the correct form my_document.xml and populates internal systems
def self.from_xml(xml)
# Reads the XML and populates:
doc = ALibrary.load(xml)
#number = doc.xpath('/number').text()
#distance = doc.xpath('/distance').text()
#distance_units = doc.xpath('/distance').attr('units') # Or whatever
end
def to_xml
# Jiggery pokery
end
end
So that now I can do:
require 'awesomelibrary'
awesome_class = AwesomeLibrary.load_from_xsd('my_document_type.xsd')
doc = awesome_class.from_xml('my_document.xml')
p doc.distance # => 20
p doc.distance_units # => 'km'
And I can also do
doc = awesome_class.new('number' => 10, 'distance_units' => 'inches', 'distance' => '5')
p doc.to_xml
And get:
<myDocument>
<number>10</number>
<distance units="inches">5</distance>
</myDocument>
This sounds like fairly intense functionality to me, so I'm not expecting a full answer, but any tips as to libraries which already do this (I've tried using RXSD, but I can't figure out how to get it to do this) or any feasibility thoughts and so on.
Thanks in advance!
Have you tried Nokogiri? The Slop decorator implements method_missing into the document in such a way that it essentially duplicates the functionality you're looking for.

List dynamic attributes in a Mongoid Model

I have gone over the documentation, and I can't find a specific way to go about this. I have already added some dynamic attributes to a model, and I would like to be able to iterate over all of them.
So, for a concrete example:
class Order
include Mongoid::Document
field :status, type: String, default: "pending"
end
And then I do the following:
Order.new(status: "processed", internal_id: "1111")
And later I want to come back and be able to get a list/array of all the dynamic attributes (in this case, "internal_id" is it).
I'm still digging, but I'd love to hear if anyone else has solved this already.
Just include something like this in your model:
module DynamicAttributeSupport
def self.included(base)
base.send :include, InstanceMethods
end
module InstanceMethods
def dynamic_attributes
attributes.keys - _protected_attributes[:default].to_a - fields.keys
end
def static_attributes
fields.keys - dynamic_attributes
end
end
end
and here is a spec to go with it:
require 'spec_helper'
describe "dynamic attributes" do
class DynamicAttributeModel
include Mongoid::Document
include DynamicAttributeSupport
field :defined_field, type: String
end
it "provides dynamic_attribute helper" do
d = DynamicAttributeModel.new(age: 45, defined_field: 'George')
d.dynamic_attributes.should == ['age']
end
it "has static attributes" do
d = DynamicAttributeModel.new(foo: 'bar')
d.static_attributes.should include('defined_field')
d.static_attributes.should_not include('foo')
end
it "allows creation with dynamic attributes" do
d = DynamicAttributeModel.create(age: 99, blood_type: 'A')
d = DynamicAttributeModel.find(d.id)
d.age.should == 99
d.blood_type.should == 'A'
d.dynamic_attributes.should == ['age', 'blood_type']
end
end
this will give you only the dynamic field names for a given record x:
dynamic_attribute_names = x.attributes.keys - x.fields.keys
if you use additional Mongoid features, you need to subtract the fields associated with those features:
e.g. for Mongoid::Versioning :
dynamic_attribute_names = (x.attributes.keys - x.fields.keys) - ['versions']
To get the key/value pairs for only the dynamic attributes:
make sure to clone the result of attributes(), otherwise you modify x !!
attr_hash = x.attributes.clone #### make sure to clone this, otherwise you modify x !!
dyn_attr_hash = attr_hash.delete_if{|k,v| ! dynamic_attribute_names.include?(k)}
or in one line:
x.attributes.clone.delete_if{|k,v| ! dynamic_attribute_names.include?(k)}
So, what I ended up doing is this. I'm not sure if it's the best way to go about it, but it seems to give me the results I'm looking for.
class Order
def dynamic_attributes
self.attributes.delete_if { |attribute|
self.fields.keys.member? attribute
}
end
end
Attributes appears to be a list of the actual attributes on the object, while fields appears to be a hash of the fields that were predefined. Couldn't exactly find that in the documentation, but I'm going with it for now unless someone else knows of a better way!
try .methods or .instance_variables
Not sure if I liked the clone approach, so I wrote one too. From this you could easily build a hash of the content too. This merely outputs it all the dynamic fields (flat structure)
(d.attributes.keys - d.fields.keys).each {|a| puts "#{a} = #{d[a]}"};
I wasn't able to get any of the above solutions to work (as I didn't want to have to add slabs and slabs of code to each model, and, for some reason, the attributes method does not exist on a model instance, for me. :/), so I decided to write my own helper to do this for me. Please note that this method includes both dynamic and predefined fields.
helpers/mongoid_attribute_helper.rb:
module MongoidAttributeHelper
def self.included(base)
base.extend(AttributeMethods)
end
module AttributeMethods
def get_all_attributes
map = %Q{
function() {
for(var key in this)
{
emit(key, null);
}
}
}
reduce = %Q{
function(key, value) {
return null;
}
}
hashedResults = self.map_reduce(map, reduce).out(inline: true) # Returns an array of Hashes (i.e. {"_id"=>"EmailAddress", "value"=>nil} )
# Build an array of just the "_id"s.
results = Array.new
hashedResults.each do |value|
results << value["_id"]
end
return results
end
end
end
models/user.rb:
class User
include Mongoid::Document
include MongoidAttributeHelper
...
end
Once I've added the aforementioned include (include MongoidAttributeHelper) to each model which I would like to use this method with, I can get a list of all fields using User.get_all_attributes.
Granted, this may not be the most efficient or elegant of methods, but it definitely works. :)

Resources