I am trying to get the yard-rpec-plugin to work.
For the given example it works, but when I add a module (as my code has), it does not give the rspec info in the doc.
To give an example, the following does not work, but leave out the 'Module Test' and it works.
module Test
class String
# Pig latin of a String
def pig_latin
self[1..-1] + self[0] + "ay"
end
end
end
While going through the code I noticed that in the RSpecItHandler, the following returns a Proxy when using modules. It seems part of the problem.
obj = P(owner[:spec])
Apparently the owner (the describe handler) is not yet in the namespace?
PS. The documentation for yard is actually quite good (and I read it), but I cannot find information about this specific part.
If feel sympathy for Thermatix's question, but it is closed as unclear (Yardoc Handlers). Therefore I ask this more specific question.
I went through the code base and found that the following works
Instead of
P(owner[:spec])
Use
P(namespace, owner[:spec])
That takes care of the name-spacing of modules...
Related
Tldr: how do I 'include Shoes methods' into the Array class and classes ive created, with minimal code, without totally restructuring everything?
I've written a functioning program in Ruby, and now I want to make a Shoes app from it.
I'm having the problem described at the beginning of the manual - Shoes.app is a sort of block in itself, so self always refers to it, and Shoes methods like "para" aren't necessarily going to be available everywhere the way "puts" is in Ruby. But I'm not smart enough to fix it (I've only just got my head around using self and return in pure Ruby, bear with me)
For example, I've created a new method for Array: putdata, which loops through a student's test score array displaying each automatically as a list:
self.each do |ea|
puts/para "#{ea.topic}: #{ea.score}"
end
Works in ruby. Doesn't work in Shoes: Array class doesn't have access to the method para. I've tried:
making Array < Shoes (it really doesn't like that)
adding stack.app do...end at various places in the program (no impact)
trying to call Shoes::para instead of para (farts)
I've tried using require 'file with all my classes and methods in.rb' instead of the same code in the file (reports no method for class)
tried requiring my code directly before calling a method, to ensure my code is in the scope of Shoes (reports no method for class)
making my custom classes (Course and Student) < Shoes, so it'd have access to its methods (causes a runtime error)
I've got it to function by:
1. Removing this bit of code from the Array class, and making it a floating/generic method rather than an Array method
2. Private method error --> then rephrasing it so instead of an Array method (array.putdata) it's a generic method which takes an array as an argument (putdata(array))
But I really, really don't want to go through my code and individually un-organise it like this.
It's my first 1000 line program, with 42 methods, and I worked hard on making it as maintainable and neat as possible, with everything tucked away in classes or methods for easy upkeep. I got it from everything in massive, step-by-step generic methods down to lots of snappy ones, which seemed a bit more like how OOP is meant to go. Now the only way I can see to make this work is to UN-OOP it, and have no class methods or anything.
I was hoping I could Shoes the program fairly seamlessly from this tidy, functional back-end: the Ruby program has lots of "if string == "SAVE", save(student); else...", so I was hoping to straightforwardly pop in "button.click {save(student)}" with the same back code.
#
Is there something fundamental I'm missing to let me do this? And can I fix the para problem easily, seeing as all my classes contain ways of displaying their own data? I'd like to copypasta "include 'Shoes methods'" at the top of each class and be done.
Or do I need to be writing with the GUI in mind from the start in future?
(Info about my program:
Layout is a series of pages, linked from a sidebar, using index with linked pages as copied straight from the Nobody Knows Shoes book, or the class-book sample.
Students can input their new levels, and view a readout of their current progress.
There are generic methods for major "parts" of the program, which have things like the title of the page and some instructions, and which then call on student objects or Module methods to do the things as instructed by the user.
Higher up: student is a custom class, with methods like "save", "display flattened data ", "add one to your level IF this ELSE don't", and associated bits of data, like an array with all their course objects in.
Each course is also a custom class ("Module"), which has the score, the module name etc as variables, and some tiny methods like display formatted name, or add one to this module.)
I'm glad to see a question about shoes, it's been a long time.
You'r new on SO so first: your question is way too elaborated, too much to read and far too little information to help you.
You need to provide piecess of code that give error or don't do what you expect, things we can take over and try. This means extracting from your code tests or pieces of code that run by themself and show the problem.
We also need to know which Ruby version and which version and color of shoes you are using. The example I'll be using is green shoes.
I'm sure the following isn't exactly what you were after but I've made a sample based on your description of an Array that needs to be listed both by puts and para.
Change the question or make a new one if this is not what you are after.
require 'green_shoes'
s = Struct.new(:topic, :score)
s1 = s.new("test1", 1)
s2 = s.new("test2", 2)
A = [s1, s2]
class Array
def putsdata(shoes = nil)
if shoes.class == Shoes::App
self.each do |ea|
shoes.para "#{ea.topic}: #{ea.score}"
end
else
self.each do |ea|
puts "#{ea.topic}: #{ea.score}"
end
end
end
end
A.putsdata
# gives in the console
# test1: 1
# test2: 2
Shoes.app do
A.putsdata(self)
end
# gives in a graphic window
# test1: 1
# test2: 2
The puts also works in the shoes block, but of course the result doesn't come in the graphic window but on the console where you started, after the first list.
I'm creating a directed_graph class in Ruby to practice using RSpec. I keep getting the above error (at line 13, which is the line below with "eql(0)" on it).
I don't really understand the error, especially since this RSpec code looks very similar to other RSpec code I've written for other projects that works.
require "directed_graph"
include directed_graph
describe directed_graph do
describe ".vertices" do
context "given an empty graph" do
it "returns an empty hash" do
g = directed_graph.new()
expect(g.vertices().length()).to() eql(0)
end
end
end
end
EDIT: I believe the problem was (1) directed_graph was a class, and classes must start with uppercase letters (so I renamed is DirectedGraph), and (2) you're not supposed to write "include" for classes.
I fixed those two, and my code seems to be runnign fine for now. I'm going to leave this up here in case I missed something big.
I believe the code should look like this:
require "directed_graph"
include DirectedGraph
describe DirectedGraph do
describe ".vertices" do
context "given an empty graph" do
it "returns an empty hash" do
expect(directed_graph.new.vertices.length).to eql(0)
end
end
end
end
Let me explain why. First include usually includes Classes/Modules. Classes and modules in ruby are denoted with Capital Letters for each part of their name (also know as UpperCamelCase). When you describe a class in in rspec, you should also use UpperCamelCase. I also cleaned up the code a little bit to make it easier to read. You don't always need the () to denote a function. It is implied. But sometimes you do need it, for example with the expect function.
I'm interested in building a DSL in Ruby for use in parsing microblog updates. Specifically, I thought that I could translate text into a Ruby string in the same way as the Rails gem allows "4.days.ago". I already have regex code that will translate the text
#USER_A: give X points to #USER_B for accomplishing some task
#USER_B: take Y points from #USER_A for not giving me enough points
into something like
Scorekeeper.new.give(x).to("USER_B").for("accomplishing some task").giver("USER_A")
Scorekeeper.new.take(x).from("USER_A").for("not giving me enough points").giver("USER_B")
It's acceptable to me to formalize the syntax of the updates so that only standardized text is provided and parsed, allowing me to smartly process updates. Thus, it seems it's more a question of how to implement the DSL class. I have the following stub class (removed all error checking and replaced some with comments to minimize paste):
class Scorekeeper
attr_accessor :score, :user, :reason, :sender
def give(num)
# Can 'give 4' or can 'give a -5'; ensure 'to' called
self.score = num
self
end
def take(num)
# ensure negative and 'from' called
self.score = num < 0 ? num : num * -1
self
end
def plus
self.score > 0
end
def to (str)
self.user = str
self
end
def from(str)
self.user = str
self
end
def for(str)
self.reason = str
self
end
def giver(str)
self.sender = str
self
end
def command
str = plus ? "giving ##{user} #{score} points" : "taking #{score * -1} points from ##{user}"
"##{sender} is #{str} for #{reason}"
end
end
Running the following commands:
t = eval('Scorekeeper.new.take(4).from("USER_A").for("not giving me enough points").giver("USER_B")')
p t.command
p t.inspect
Yields the expected results:
"#USER_B is taking 4 points from #USER_A for not giving me enough points"
"#<Scorekeeper:0x100152010 #reason=\"not giving me enough points\", #user=\"USER_A\", #score=4, #sender=\"USER_B\">"
So my question is mainly, am I doing anything to shoot myself in the foot by building upon this implementation? Does anyone have any examples for improvement in the DSL class itself or any warnings for me?
BTW, to get the eval string, I'm mostly using sub/gsub and regex, I figured that's the easiest way, but I could be wrong.
Am I understanding you correctly: you want to take a string from a user and cause it to trigger some behavior?
Based on the two examples you listed, you probably can get by with using regular expressions.
For example, to parse this example:
#USER_A: give X points to #USER_B for accomplishing some task
With Ruby:
input = "#abe: give 2 points to #bob for writing clean code"
PATTERN = /^#(.+?): give ([0-9]+) points to #(.+?) for (.+?)$/
input =~ PATTERN
user_a = $~[1] # => "abe"
x = $~[2] # => "2"
user_b = $~[3] # => "bob"
why = $~[4] # => "writing clean code"
But if there is more complexity, at some point you might find it easier and more maintainable to use a real parser. If you want a parser that works well with Ruby, I recommend Treetop: http://treetop.rubyforge.org/
The idea of taking a string and converting it to code to be evaled makes me nervous. Using eval is a big risk and should be avoided if possible. There are other ways to accomplish your goal. I'll be happy to give some ideas if you want.
A question about the DSL you suggest: are you going to use it natively in another part of your application? Or do just plan on using it as part of the process to convert the string into the behavior you want? I'm not sure what is best without knowing more, but you may not need the DSL if you are just parsing the strings.
This echoes some of my thoughts on a tangental project (an old-style text MOO).
I'm not convinced that a compiler-style parser is going to be the best way for the program to deal with the vaguaries of english text. My current thoughts have me splitting up the understanding of english into seperate objects -- so a box understands "open box" but not "press button", etc. -- and then having the objects use some sort of DSL to call centralised code that actually makes things happen.
I'm not sure that you've got to the point where you understand how the DSL is actually going to help you. Maybe you need to look at how the english text gets turned into DSL, first. I'm not saying that you don't need a DSL; you might very well be right.
As for hints as to how to do that? Well, I think if I were you I would be looking for specific verbs. Each verb would "know" what sort of thing it should expect from the text around it. So in your example "to" and "from" would expect a user immediately following.
This isn't especially divergent from the code you've posted here, IMO.
You might get some milage out of looking at the answers to my question. One commenter pointed me to the Interpreter Pattern, which I found especially enlightening: there's a nice Ruby example here.
Building on #David_James' answer, I've come up with a regex-only solution to this since I'm not actually using the DSL anywhere else to build scores and am merely parsing out points to users. I've got two patterns that I'll use to search:
SEARCH_STRING = "#Scorekeeper give a healthy 4 to the great #USER_A for doing something
really cool.Then give the friendly #USER_B a healthy five points for working on this.
Then take seven points from the jerk #USER_C."
PATTERN_A = /\b(give|take)[\s\w]*([+-]?[0-9]|one|two|three|four|five|six|seven|eight|nine|ten)[\s\w]*\b(to|from)[\s\w]*#([a-zA-Z0-9_]*)\b/i
PATTERN_B = /\bgive[\s\w]*#([a-zA-Z0-9_]*)\b[\s\w]*([+-]?[0-9]|one|two|three|four|five|six|seven|eight|nine|ten)/i
SEARCH_STRING.scan(PATTERN_A) # => [["give", "4", "to", "USER_A"],
# ["take", "seven", "from", "USER_C"]]
SEARCH_STRING.scan(PATTERN_B) # => [["USER_B", "five"]]
The regex might be cleaned up a bit, but this allows me to have syntax that allows a few fun adjectives while still pulling the core information using both "name->points" and "points->name" syntaxes. It does not allow me to grab the reason, but that's so complex that for now I'm going to just store the entire update, since the whole update will be related to the context of each score anyway in all but outlier cases. Getting the "giver" username can be done elsewhere as well.
I've written up a description of these expressions as well, in hopes that other people might find that useful (and so that I can go back to it and remember what that long string of gobbledygook means :)
I have a class that is provided to me by an external library. I have created a subclass of this class. I also have an instance of the original class.
I now want to turn this instance into an instance of my subclass without changing any properties that the instance already has (except for those that my subclass overrides anyway).
The following solution seems to work.
# This class comes from an external library. I don't (want) to control
# it, and I want to be open to changes that get made to the class
# by the library provider.
class Programmer(object):
def __init__(self,name):
self._name = name
def greet(self):
print "Hi, my name is %s." % self._name
def hard_work(self):
print "The garbage collector will take care of everything."
# This is my subclass.
class C_Programmer(Programmer):
def __init__(self, *args, **kwargs):
super(C_Programmer,self).__init__(*args, **kwargs)
self.learn_C()
def learn_C(self):
self._knowledge = ["malloc","free","pointer arithmetic","curly braces"]
def hard_work(self):
print "I'll have to remember " + " and ".join(self._knowledge) + "."
# The questionable thing: Reclassing a programmer.
#classmethod
def teach_C(cls, programmer):
programmer.__class__ = cls # <-- do I really want to do this?
programmer.learn_C()
joel = C_Programmer("Joel")
joel.greet()
joel.hard_work()
#>Hi, my name is Joel.
#>I'll have to remember malloc and free and pointer arithmetic and curly braces.
jeff = Programmer("Jeff")
# We (or someone else) makes changes to the instance. The reclassing shouldn't
# overwrite these.
jeff._name = "Jeff A"
jeff.greet()
jeff.hard_work()
#>Hi, my name is Jeff A.
#>The garbage collector will take care of everything.
# Let magic happen.
C_Programmer.teach_C(jeff)
jeff.greet()
jeff.hard_work()
#>Hi, my name is Jeff A.
#>I'll have to remember malloc and free and pointer arithmetic and curly braces.
However, I'm not convinced that this solution doesn't contain any caveats I haven't thought of (sorry for the triple negation), especially because reassigning the magical __class__ just doesn't feel right. Even if this works, I can't help the feeling there should be a more pythonic way of doing this.
Is there?
Edit: Thanks everyone for your answers. Here is what I get from them:
Although the idea of reclassing an instance by assigning to __class__ is not a widely used idiom, most answers (4 out of 6 at the time of writing) consider it a valid approach. One anwswer (by ojrac) says that it's "pretty weird at first glance," with which I agree (it was the reason for asking the question). Only one answer (by Jason Baker; with two positive comments & votes) actively discouraged me from doing this, however doing so based on the example use case moreso than on the technique in general.
None of the answers, whether positive or not, finds an actual technical problem in this method. A small exception is jls who mentions to beware of old-style classes, which is likely true, and C extensions. I suppose that new-style-class-aware C extensions should be as fine with this method as Python itself (presuming the latter is true), although if you disagree, keep the answers coming.
As to the question of how pythonic this is, there were a few positive answers, but no real reasons given. Looking at the Zen (import this), I guess the most important rule in this case is "Explicit is better than implicit." I'm not sure, though, whether that rule speaks for or against reclassing this way.
Using {has,get,set}attr seems more explicit, as we are explicitly making our changes to the object instead of using magic.
Using __class__ = newclass seems more explicit because we explicitly say "This is now an object of class 'newclass,' expect a different behaviour" instead of silently changing attributes but leaving users of the object believing they are dealing with a regular object of the old class.
Summing up: From a technical standpoint, the method seems okay; the pythonicity question remains unanswered with a bias towards "yes."
I have accepted Martin Geisler's answer, because the Mercurial plugin example is a quite strong one (and also because it answered a question I even hadn't asked myself yet). However, if there are any arguments on the pythonicity question, I'd still like to hear them. Thanks all so far.
P.S. The actual use case is a UI data control object that needs to grow additional functionality at runtime. However, the question is meant to be very general.
Reclassing instances like this is done in Mercurial (a distributed revision control system) when extensions (plugins) want to change the object that represent the local repository. The object is called repo and is initially a localrepo instance. It is passed to each extension in turn and, when needed, extensions will define a new class which is a subclass of repo.__class__ and change the class of repo to this new subclass!
It looks like this in code:
def reposetup(ui, repo):
# ...
class bookmark_repo(repo.__class__):
def rollback(self):
if os.path.exists(self.join('undo.bookmarks')):
util.rename(self.join('undo.bookmarks'), self.join('bookmarks'))
return super(bookmark_repo, self).rollback()
# ...
repo.__class__ = bookmark_repo
The extension (I took the code from the bookmarks extension) defines a module level function called reposetup. Mercurial will call this when initializing the extension and pass a ui (user interface) and repo (repository) argument.
The function then defines a subclass of whatever class repo happens to be. It would not suffice to simply subclass localrepo since extensions need to be able to extend each other. So if the first extension changes repo.__class__ to foo_repo, the next extension should change repo.__class__ to a subclass of foo_repo and not just a subclass of localrepo. Finally the function changes the instanceø's class, just like you did in your code.
I hope this code can show a legitimate use of this language feature. I think it's the only place where I've seen it used in the wild.
I'm not sure that the use of inheritance is best in this case (at least with regards to "reclassing"). It seems like you're on the right track, but it sounds like composition or aggregation would be best for this. Here's an example of what I'm thinking of (in untested, pseudo-esque code):
from copy import copy
# As long as none of these attributes are defined in the base class,
# this should be safe
class SkilledProgrammer(Programmer):
def __init__(self, *skillsets):
super(SkilledProgrammer, self).__init__()
self.skillsets = set(skillsets)
def teach(programmer, other_programmer):
"""If other_programmer has skillsets, append this programmer's
skillsets. Otherwise, create a new skillset that is a copy
of this programmer's"""
if hasattr(other_programmer, skillsets) and other_programmer.skillsets:
other_programmer.skillsets.union(programmer.skillsets)
else:
other_programmer.skillsets = copy(programmer.skillsets)
def has_skill(programmer, skill):
for skillset in programmer.skillsets:
if skill in skillset.skills
return True
return False
def has_skillset(programmer, skillset):
return skillset in programmer.skillsets
class SkillSet(object):
def __init__(self, *skills):
self.skills = set(skills)
C = SkillSet("malloc","free","pointer arithmetic","curly braces")
SQL = SkillSet("SELECT", "INSERT", "DELETE", "UPDATE")
Bob = SkilledProgrammer(C)
Jill = Programmer()
teach(Bob, Jill) #teaches Jill C
has_skill(Jill, "malloc") #should return True
has_skillset(Jill, SQL) #should return False
You may have to read more about sets and arbitrary argument lists if you aren't familiar with them to get this example.
This is fine. I've used this idiom plenty of times. One thing to keep in mind though is that this idea doesn't play well with old-style classes and various C extensions. Normally this wouldn't be an issue, but since you are using an external library you'll just have to make sure you're not dealing with any old-style classes or C extensions.
"The State Pattern allows an object to alter its behavior when its internal state changes. The object will appear to change it's class." - Head First Design Pattern. Something very similar write Gamma et.al. in their Design Patterns book. (I have it at my other place, so no quote). I think that's the whole point of this design pattern. But if I can change the class of an object at runtime, most of the time i don't need the pattern (there are cases when State Pattern does more than simulate a class change).
Also, changing class at runtime doesn't always work:
class A(object):
def __init__(self, val):
self.val = val
def get_val(self):
return self.val
class B(A):
def __init__(self, val1, val2):
A.__init__(self, val1)
self.val2 = val2
def get_val(self):
return self.val + self.val2
a = A(3)
b = B(4, 6)
print a.get_val()
print b.get_val()
a.__class__ = B
print a.get_val() # oops!
Apart from that, I consider changing class at runtime Pythonic and use it from time to time.
Heheh, fun example.
"Reclassing" is pretty weird, at first glance. What about the 'copy constructor' approach? You can do this with the Reflection-like hasattr, getattr and setattr. This code will copy everything from one object to another, unless it already exists. If you don't want to copy methods, you can exclude them; see the commented if.
class Foo(object):
def __init__(self):
self.cow = 2
self.moose = 6
class Bar(object):
def __init__(self):
self.cat = 2
self.cow = 11
def from_foo(foo):
bar = Bar()
attributes = dir(foo)
for attr in attributes:
if (hasattr(bar, attr)):
break
value = getattr(foo, attr)
# if hasattr(value, '__call__'):
# break # skip callables (i.e. functions)
setattr(bar, attr, value)
return bar
All this reflection isn't pretty, but sometimes you need an ugly reflection machine to make cool stuff happen. ;)
This technique seems reasonably Pythonic to me. Composition would also be a good choice, but assigning to __class__ is perfectly valid (see here for a recipe that uses it in a slightly different way).
In ojrac's answer, the break breaks out of the for-loop and doesn't test any more attributes. I think it makes more sense to just use the if-statement to decide what to do with each attribute one at a time, and continue through the for-loop over all attributes. Otherwise, I like ojrac's answer, as I too see assigning to __class__ as weird. (I'm a beginner with Python and as far as I remember this is my first post to StackOverFlow. Thanks for all the great information!!)
So I tried to implement that. I noticed that dir() doesn't list all the attributes. http://jedidjah.ch/code/2013/9/8/wrong_dir_function/ So I added 'class', 'doc', 'module' and 'init' to the list of things to add if they're not there already, (although they're probably all already there), and wondered whether there were more things dir misses. I also noticed that I was (potentially) assigning to 'class' after having said that was weird.
I will say this is perfectly fine, if it works for you.
(sorry I should have been clearer with the code the first time I posted this. Hope this makes sense)
File "size_specification.rb"
class SizeSpecification
def fits?
end
end
File "some_module.rb"
require 'size_specification'
module SomeModule
def self.sizes
YAML.load_file(File.dirname(__FILE__) + '/size_specification_data.yml')
end
end
File "size_specification_data.yml
---
- !ruby/object:SizeSpecification
height: 250
width: 300
Then when I call
SomeModule.sizes.first.fits?
I get an exception because "sizes" are Object's not SizeSpecification's so they don't have a "fits" function.
Are your settings and ruby installation ok? I created those 3 files and wrote what follows in "test.rb"
require 'yaml'
require "some_module"
SomeModule.sizes.first.fits?
Then I ran it.
$ ruby --version
ruby 1.8.6 (2008-06-20 patchlevel 230) [i486-linux]
$ ruby -w test.rb
$
No errors!
On second reading I'm a little confused, you seem to want to mix the class into module, which is porbably not so advisable. Also is the YAML supposed to load an array of the SizeSpecifications?
It appears to be that you're not mixing the Module into your class. If I run the test in irb then the require throws a LoadError. So I assume you've put two files together, if not dump it.
Normally you'd write the functionality in the module, then mix that into the class. so you may modify your code like this:
class SizeSpecification
include SomeModule
def fits?
end
end
Which will allow you to then say:
SizeSpecification::SomeModule.sizes
I think you should also be able to say:
SizeSpecification.sizes
However that requires you to take the self off the prefix of the sizes method definition.
Does that help?
The question code got me a little confused.
In general with Ruby, if that happens it's a good sign that I am trying to do things the wrong way.
It might be better to ask a question related to your actual intended outcome, rather than the specifics of a particular 'attack' on your problem. They we can say 'nonono, don't do that, do THIS' or 'ahhhhh, now I understand what you wanna do'