I'm trying to figure out how inheritance works in coffeescript. Here's a simplified example of my code:
class Parent
constructor: (attrs) ->
for own name,value of attrs
this[name] = value
Parent.from_json_array = (json, callback) ->
for item in JSON.parse(json)
obj = new ChildA item # [1]
callback obj
class ChildA extends Parent
class ChildB extends Parent
ChildA.from_json_array("[{foo: 1}, {foo: 2}]") (obj) ->
console.log obj.foo
What do I need to put on the line marked [1] to use the correct child class here? This works, but only creates objects with a prototype of ChildA. I've tried something like:
Parent.from_json_array = (json, callback) ->
klass = this.prototype
for item in JSON.parse(json)
obj = klass.constructor item # [1]
callback obj
... but this leaves obj as undefined in my callback function (TypeError: Cannot read property 'foo' of undefined".
Whats the magic incantation in CoffeeScript to be able to create a new object of a class, where the class is variable?
Nevermind, I figured it out:
Parent.from_json_array = (json, callback) ->
klass = this
for item in JSON.parse(json)
obj = new klass item
callback obj
Turns out you can just new a class stored in a variable. I thought I had tried this before, but was getting a syntax error.
Related
Class A {
String nameA
B b
}
Class B {
String nameB
}
So within my controller right now I have: def temp = AService.get(id) and I want to add a B object to temp.
I have seen things like: temp.addToB({b params}) but it did not work for me. How can I achieve this?
I have seen things like temp.addToB({b params}) but I have had not
success.
If you have a reference to an instance of A and you want to initialize the b property in that instance, you can use Groovy's property assignment support to do that.
A someA = new A()
someA.b = new B()
A someA = aService.get(id)
someA.b = new B()
A someA = aService.get(id)
someA.b = bService.get(someOtherId)
Etc.
I want to create a JSON object out of ruby object on view file like
:coffeescript
files = {}
- #filelist.each do |f|
= files[f[0]] = f[1]
console.log(files)
it gives me an "Unexpected logic" error
following is array declared in controller
#filelist = Array.new
#filelist.push(['ref','count'])
#filelist.push(['input1','count'])
#filelist.push(['input2','count'])
In your view you first have to convert ruby array to json (inside view):
var filelists = $.parseJSON(<%= #filelist.to_json %>);
Then create a json object in view:
var jsonObj = {};
$.each(filelists, function(obj,index){
jsonObj[obj[0]] = obj[1];
});
I have a quick problem that probably comes down to something stupid. I have a class that extends OAuth::AccessToken and uses instance variables (#) so that each time it constructs an object, those variables will be unique that instance. However, when I try to return the final object from this class, I get an error. A quick example:
require 'oauth'
class OauthFigshare < OAuth::AccessToken
def initialize (consumerkey, consumersecret, accesstoken, accesstokensecret)
#consumerkey = consumerkey
#consumersecret = consumersecret
#accesstoken = accesstoken
#accesstokensecret = accesstokensecret
#apiurl = "http://api.figshare.com"
#consumer = OAuth::Consumer.new(#consumerkey,#consumersecret,{:site=> #apiurl})
#token = { :oauth_token => #accesstoken, :oauth_token_secret => #accesstokensecret}
puts #consumer.class
puts #token
#client = OAuth::AccessToken.from_hash(#consumer, #token)
puts #client
puts #client.get('/v1/my_data/articles')
return #client
end
end
The problem is that when I check inside the class to see if the token is working, it does. However, when I check against the constructed object outside the class, it doesn't work.
#client.get(url) returns Net::HTTPOk calling from in the class
auth = OauthFigshare.new(inputs)
auth.get(url)
This returns Net::HTTPUnauthorized
What am I not getting about scope here?
Edit to include actual class
The return value of the initialize method is not used. It seems like you actually want to override self.new instead.
If not, is there anything like this on the horizon?
This is the one feature of JavaScript, Ruby, and Perl that I can't live without. I know you can fake it with a hash member, but I want to be able to create (arbitrary) "first class" members from a parser.
Currently there's nothing that can set a field that doesn't yet exist. The mirror API can be used to set fields that already exist, and may eventually be extended to support defining new fields dynamically.
You can also use the "noSuchMethod" method on a class to intercept setter / getter, and store the received value in a map.
For example (I can't remember the syntax exactly...):
class Foo {
var _dynamicProperties = new Map<String,Object>();
noSuchMethod(String function_name, List args) {
if (args.length == 0 && function_name.startsWith("get:")) {
// Synthetic getter
var property = function_name.replaceFirst("get:", "");
if (_dynamicProperties.containsKey(property)) {
return _dynamicProperties[property];
}
}
else if (args.length == 1 && function_name.startsWith("set:")) {
// Synthetic setter
var property = function_name.replaceFirst("set:", "");
// If the property doesn't exist, it will only be added
_dynamicProperties[property] = args[0];
return _dynamicProperties[property];
}
super.noSuchMethod(function_name, args)
}
}
And then you can use this in your code as follows:
var foo = new Foo();
foo.bar = "Hello, World!";
print(foo.bar);
Of course, this can lead to typos that will not be checked by the type checker, e.g.:
foo.bar = "Hello";
foo.baz = "Hello, World!"; // Typo, meant to update foo.bar.
There are ways you have type-checker validation by using redirecting factory constructors and an implied interface, but then it starts to get complicated.
Side note: This is what JsonObject uses to convert a JSON map to a class type syntax.
I'm trying to create a custom attr_accessor, but can't seem to get it to work. Instead of returning the value assigned to the writer, it returns the instance variable. Any ideas?
class Object
def custom_attr_accessor(klass, attribute)
ivar = "##{attribute}".to_sym
writer_body = lambda { |arg| instance_variable_set(ivar, arg) }
reader_body = lambda { ivar }
klass.send(:define_method, "#{attribute}=".to_sym, &writer_body)
klass.send(:define_method, "#{attribute}".to_sym, &reader_body)
end
end
class Person
end
custom_attr_accessor(Person, :age)
me = Person.new
me.age = 100
puts me.age
=> #age
Just like you did a instance_variable_set, you need instance_variable_get:
reader_body = lambda { instance_variable_get(ivar) }
BTW, extending Object and passing a class is not very pretty. Try to make it Persion. custom_attr_accessor(:age), that would be much more OOP.