How to access the parent class variables from an anonymous class in JRuby?
(without using static variables)
class MyJRubyClass
def initialize
#var1 = 1
#var2 = Class.new{
def Method1
#var1 = #var1 + 1
print #var1
end
}.new
#var2.Method1()
end
end
Thank you.
it always needs a bit of time (and practice) to get used to a new language.
the concept of Java's inner classes having 'exclusive' parent class access has no adequate in Ruby.
while its useful for related classes to co-operate on the internals, from an OOP stand-point it's not blessed as objects should be "black-boxes" cooperating using messages. this is somehow Ruby's approach.
on the other hand Ruby does not hide anything as it has reflection APIs to e.g. retrieve instance variables (the example prefers exposing an attribute reader/writer) :
class MyJRubyClass
attr_accessor :var1
def initialize
#var1 = 1
klass2 = Class.new do
def initialize(parent); #parent = parent end
def Method1
print #parent.var1 = #parent.var1 + 1
# without attr accessor :
#var1 = #parent.instance_variable_get(:#var1)
##parent.instance_varialbe_set(:#var1, var1 + 1)
end
end
#var2 = klass2.new(self)
#var2.Method1()
end
end
Related
I'm using SQLAlchemy to map a class:
class Model(sqlalchemy.declarative_base()):
attr_a = Column(String)
attr_b = Column(Integer)
attr_c = Column(Integer)
aggr = column_property(attr_b + attr_c IF attr_a=='go' ELSE attr_b - attr_c)
Last line is pseoudo code that requires some conditional logic. Is such logic even possible inside column_property? How can I implement it as a simple conditional aggregate?
Actually it turns out to be a common technique, sqlalchemy provides a tool set inside sqlalchemy.sql, one can easily write SQL logic such as case:
from sqlalchemy.sql import case
...
aggr = column_property(case([(attr_a=="go", attr_b + attr_c), (attr_a=="return", attr_b + attr_c + attrition]
Just note here that case takes a python iterable as parameter.
I've become confused while writing custom to_json and from_json methods for a class. I have actually found a solution, but don't understand why it works, nor why my initial attempt does not work.
I have a People class that initializes by taking an instance of a Person class as a paramater.
The to_json/from_json methods in Person have been copied in from a generic
external module, and therefore a bit wordy...but worked when I tested it on an individual instance of a Person object.
The problem comes when re-creating the People object from JSON. For the #person instance variable, I'm expecting:
#<Person:0x00000001a0b440 #name="Jon", #age=22, #gender="male">
Instead, I'm getting #person as an array (and thus, only the keys):
#<People:0x00000001b5c038 #person=["#name", "#age", "#gender"]>
Full code is as follows:
require "json"
class Person
attr_accessor :name, :age, :gender
def initialize(name, age, gender)
#name = name
#age = age
#gender = gender
end
def to_json
obj = {}
instance_variables.map do |var|
obj[var] = instance_variable_get(var)
end
JSON.dump(obj)
end
def from_json(string)
obj = JSON.parse(string)
obj.keys.each do |key|
instance_variable_set(key, obj[key])
end
end
end
class People
attr_accessor :person
def initialize(person)
#person = person
end
def to_json
obj = {}
obj[:person] = #person.to_json
JSON.dump(obj)
end
def from_json(string)
obj = JSON.parse(string, {:symbolize_names => true})
person = Person.new("", 0, "")
#person = person.from_json(obj[:person])
end
def <<(person)
#persons << person
end
end
After re-writing the to_json and from_json methods as below, the problem seems to have been solved...and now correctly re-assembles #person as expected.
def to_json
obj = {}
obj[:persons] = [#person.to_json]
JSON.dump(obj)
end
def from_json(string)
obj = JSON.parse(string, {:symbolize_names => true})
persons = []
obj[:persons].each do |person_string|
person = Person.new("", 0, "")
person.from_json(person_string)
persons << person
end
#person = persons[0]
end
I'm happy to have found a solution, but I can't understand why encasing the single Person object in an array would solve the situation.
I'm sure there are many other ways to solve this particular situation (and other methods completely... eg: other gems, or using Rails Active Support...), but I'm simply trying to get a more solid understanding why my initial idea doesn't work...to help later on when things get more complicated.
Thank you for any help you can offer...
Your first solution works. You simply forgot to return from your method. See below:
def from_json(string)
obj = JSON.parse(string, {:symbolize_names => true})
person = Person.new("", 0, "")
#person = person.from_json(obj[:person])
obj #RETURN THE OBJECT HERE
end
In the second solution you are still missing the return value however Ruby implicitly returns the last evaluated expression from the method which by chance happens to be correct. This is the same reason why your first solution didn't work.
I have a function that is inserting a record into my DB (MySQL). It has many columns, many of which have default values in the DB. Passing in values for these variables is therefore optional.
def assign_X_to_Y( options = {} )
. . .
#bar.var1 = options[:foo]
. . .
end
I would like to do the following:
-If a variable exists (ex: options[:foo]), add it to the record I'm making.
#bar.var1 = options[:foo]
-If it doesn't, I don't want to add it--I want to use the DB default.
I know I can simply do an if:
if options[:foo]
#bar.var1 = options[:foo]
end
But I have a lot of these variables and so I think there must be a nicer way that having loads of if-statements. Something like the "if doesn't exist set to null" expression:
#bar.var1 = options[:foo] || nil
Is there anything like what I am saying? I can't use the above expression because I don't want to set it to null (which I think it would do), I want to use the default value…
Thanks in advance!
If #bar is an model you can simply pass a hash:
Bar.create(hash) # creates a Bar with the defaults from your schema
#bar.assign_attributes(hash)
#bar.update(hash) # same as object but commits the changes to the db
If bar is a Plain Old Ruby class you can give it the same functionality by:
class Bar
attr_accessor :foo
attr_accessor :baz
attr_accessor :woggle
def initialize(hash)
assign_values(hash)
end
def assign_attributes(hash)
assign_values(hash)
end
private
def assign_values(hash)
hash.each do |k,v|
send "#{k}=", v
end
end
end
Then I can simply create an object with:
Bar.new(foo: 1, baz: 3)
Note that this will respect object encapsulation - if I try to do:
Bar.new(haxxored: true)
It will raise a NoMethodError. Just like #bar.haxxored = true.
If I'm understanding your question correctly, the best way to handle this would be to use the public_send method in Ruby:
def set_new_property(obj, prop_name, prop_value)
obj.class.__send__(attr_accessor: "#{prop_name}")
obj.public_send("#{prop_name}=", prop_value)
end
Bear in mind that you'll have to set explicit attribute accessors for each potential property being assigned.
Using DataMapper Enum type for the first time, and I noticed the first value in the enum translates to a 1. I need this to be zero based to be backward compatiable with another ORM layer in a different application also reading this database.
You should be able to monkey-patch enum.rb in dm-types to support this. You will need to replace the initialize method with a slightly modified copy where #flag_map[i+1] is replaced with #flag_map[i]:
module DataMapper
class Property
class Enum < Object
def initialize(model, name, options = {})
#flag_map = {}
flags = options.fetch(:flags, self.class.flags)
flags.each_with_index do |flag, i|
#flag_map[i] = flag
end
if self.class.accepted_options.include?(:set) && !options.include?(:set)
options[:set] = #flag_map.values_at(*#flag_map.keys.sort)
end
super
end # end initialize
end # end class Enum
end # end class Property
end # end module DataMapper
I am coding a custom Liquid tag as Jekyll plugin for which I need to preserve some values until the next invocation of the tag within the current run of the jekyll build command.
Is there some global location/namespace that I could use to store and retrieve values (preferably key-value pairs / a hash)?
You could add a module with class variables for storing the persistent values, then include the module in your tag class. You would need the proper accessors depending on the type of the variables and the assignments you might want to make. Here's a trivial example implementing a simple counter that keeps track of the number of times the tag was called in DataToKeep::my_val:
module DataToKeep
##my_val = 0
def my_val
##my_val
end
def my_val= val
##my_val = val
end
end
module Jekyll
class TagWithKeptData < Liquid::Tag
include DataToKeep
def render(context)
self.my_val = self.my_val + 1
return "<p>Times called: #{self.my_val}</p>"
end
end
end
Liquid::Template.register_tag('counter', Jekyll::TagWithKeptData)