Recursive method not returning to previous line position in caller - ruby-on-rails

I have been trying to find a solution to this for some time. I have found questions and answers on recursion but nothing that seemed to fit this particular situation.
I have written a class which should go through the given folder and all subfolders and rename files and folders if a particular search pattern is found.
Everything works as expected the replaceAllInDir gets called, it replaces files and folders if needed. The next step then is to do the same for all subfolders within the given folder.
So a subfolder gets identified and replaceAllInDir gets called from within itself. Let's assum the particular subfolder called does not contain any subfolders. I would then expect that we return to the parent folder and continue looking for other subfolders. But instead control is not returned to the parent calling method and the program ends.
I am aware of other ways of solving the actual use case, but I cannot explain the behaviour of ruby.
class MultiFileAndFolderRename
attr_accessor :rootDir, :searchPattern, :replacePattern
def initialize(rootDir, searchPattern, replacePattern)
#rootDir = rootDir
#searchPattern = searchPattern
#replacePattern = replacePattern
end
def execute
replaceAllInDir(#rootDir)
end
def getValidDirEntries(dir)
dirList = Dir.entries(dir)
dirList.delete('.')
dirList.delete('..')
dirList
end
def replaceAllInDir(currentDir)
Dir.chdir(currentDir)
puts "Processing directory: " + Dir.pwd
dirList = getValidDirEntries(currentDir)
dirList.each { |dirEntry|
attemptRename(dirEntry)
}
dirList = getValidDirEntries(currentDir)
dirList.each { |dirEntry|
if File.directory?(dirEntry)
newDir = currentDir + '\\' + dirEntry
rntemp = MultiFileAndFolderRename.new(newDir, 'searchString', 'replaceString')
rntemp.replaceAllInDir(newDir)
end
}
end
def attemptRename(dirEntry)
if dirEntry.match(#searchPattern)
newname = dirEntry.to_s.sub(#searchPattern, #replacePattern)
FileUtils.mv(dirEntry.to_s, newname)
end
end
end

You have a bug. The first line of replaceAllInDir() is Dir.chdir(). chdir() changes the directory of the current process on a global scale. It's not call-stack dependent. So later when you move into a subdirectory and change into that, the change becomes permanent even if you return from the recursion.
You need to change back to the correct directory after any call to replaceAllInDir(). For example:
...
dirList.each { |dirEntry|
if File.directory?(dirEntry)
....
rntemp.replaceAllInDir(newDir)
Dir.chdir(currentDir) # <- Restore us back to the correct directory
end
}

I have tried your code, and I have found numerous errors in it. Perhaps if you fix them, your idea is working.
You should include in a library like that a part at the end that allows to call it from the shell: MultiFileAndFolderRename.new(ARGV[0], ARGV[1], ARGV[2]).execute if __FILE__ == $0 This ensures when you call the ruby code from the shell by ruby rename.rb test old new, your class will be instantiated, and the search and replace pattern will be set accordingly.
You shouldn't set the current directory, because that ensures that the line getValidDirEntries(currentDir) will not work. If you eg. call it for the directory test, and then change your current directory to test, inside the directory, getValidDirEntries('test') will not work like expected.
You should use only forward slashes instead of the double backward ones. So your code will work on Linux and Mac OS X as well.
When you instantiate the new instance of MultiFileAndFolderRename (which is not necessary), the arguments to the initializer are the wrong ones. Instead, you should use your current instance and just call self.replaceAllInDir(newDir) instead of rntemp = MultiFileAndFolderRename.new(newDir, 'searchString', 'replaceString');rntemp.replaceAllInDir(newDir).
I think the wrong instantiation is the major reason why it works not as expected, but the others should be fixed as well.

Related

Biopython : how to extract only relevant atom and save a pdb file (not locally)?

Using Biopython. I have a list of atoms. rep_atoms = [CA, CB, CD3] (Carbon atoms).
I want to save only these from any given PDB file. I don't want to save it locally; I want it to save in the memory (Lots of iteration).
I have arrived at the code below, but it saves the file locally and is very slow.
So, my goal is from each atom in PDB, if it is present in rep_atoms. Make a new_pdb store only that information so that when I call it later in my code, it should be a PDB file without getting saved in my computer in a local folder.
How do I append each atom? Printing all atoms is very fast. I want to append it, but it wouldn't be a PDB structure file. What should I do?
from Bio.PDB import .... PDBIO, Select ....
class rep_atom_Select(Select):
def accept_atom(self, atom):
if atom.get_name() in rep_atoms:
return 1
else:
return 0
def rep_atoms_pdb(input_pdb):
io = PDBIO()
io.set_structure(input_pdb)
for model in input_pdb:
for chain in model:
for residue in chain:
for atom in residue:
if atom.get_name() in rep_atoms:
print(atom)
# dnr_only = io.save("dnr_only.pdb", rep_atom_Select())
Save after the loop, once, instead of thousands of times inside the loop.
def rep_atoms_pdb(input_pdb):
my_atoms = list()
for model in input_pdb:
for chain in model:
for residue in chain:
for atom in residue:
if atom.get_name() in rep_atoms: # or if rep_atom_Select().accept_atom(atom):
my_atoms.append(atom) # or something like this
# The function returns the list of extracted atoms
return my_atoms
Your definition of rep_atom_Select() does not seem to be directly compatible with this design, nor am I sure receiving the atoms as a list is actually what you want, but this should at least give you a nudge in the right direction.
Brief reading of the Bio.PDB.PDBIO documentation suggests that you might simply want to return the actual PDBIO object. I think something like this:
class rep_atom_Select(Select):
def accept_atom(self, atom):
if atom.get_name() in rep_atoms:
return 1
else:
return 0
def rep_atoms_pdb(input_pdb):
io = rep_atom_Select()
io.set_structure(input_pdb)
return io
This is based on a very cursory reading of the documentation, but at least demonstrates how you would use your overridden class to select only some of the atoms in the input_pdb structure.

Lua - table won't insert from function

I have a Lua function where I build a table of value and attempt to add it to a global table with a named key.
The key name is pulled from the function arguments. Basically, it's a filename, and I'm pairing it up with data about the file.
Unfortunately, the global table always comes back nil. Here's my code: (let me know if you need to see more)
(Commented parts are other attempts, although many attempts have been deleted already)
Animator = Class{}
function Animator:init(atlasfile, stringatlasfriendlyname, totalanimationstates, numberofframesperstate, booleanstatictilesize)
-- Define the Animator's operation mode. Either static tile size or variable.
if booleanstatictilesize ~= false then
self.isTileSizeStatic = true
else
self.isTileSizeStatic = false
end
-- Define the total animation states (walking left, walking right, up down, etc.)
-- And then the total frames per state.
self.numAnimationStates = totalanimationstates or 1
self.numAnimationFrames = numberofframesperstate or 2
-- Assign the actual atlas file and give it a programmer-friendly name.
self.atlasname = stringatlasfriendlyname or removeFileExtension(atlasfile, 'animation')
generateAnimationQuads(atlasfile, self.atlasname, self.numAnimationStates, self.numAnimationFrames)
end
function generateAnimationQuads(atlasfile, atlasfriendlyname, states, frames)
spriteWidthDivider = atlasfile:getWidth() / frames
spriteHeightDivider = atlasfile:getHeight() / states
animationQuadArray = generateQuads(atlasfile, spriteWidthDivider, spriteHeightDivider)
animationSetValues = {atlasarray = animationQuadArray, width = spriteWidthDivider, height = spriteHeightDivider}
--gAnimationSets[#gAnimationSets+1] = atlasfriendlyname
gAnimationSets[atlasfriendlyname] = animationSetValues
--table.insert(gAnimationSets, atlasfriendlyname)
end
Note: when using print(atlasfriendlyname) and print(animationSetValues), neither are empty or nil. They both contain values.
For some reason, the line(s) that assign the key pair to gAnimationSets does not work.
gAnimationSets is defined a single time at the top of the program in main.lua, using
gAnimationSets = {}
Animator class is called during the init() function of a character class called Bug. And the Bug class is initialized in the init() function of StartState, which extends from BaseState, which simply defines dummy init(), enter(), update() etc. functions.
StartState is invoked in main.lua using the StateMachine class, where it is passed into StateMachine as a value of a global table declared in main.lua.
gAnimationSets is declared after the table of states and before invoking the state.
This is using the Love2D engine.
Sorry that I came here for help, I've been picking away at this for hours.
Edit: more testing.
Trying to print the animationQuadArray at the index gTextures['buganimation'] always returns nil. Huh?
Here's gTextures in Main.lua
gTextures = {
['background'] = love.graphics.newImage('graphics/background.png'),
['main'] = love.graphics.newImage('graphics/breakout.png'),
['arrows'] = love.graphics.newImage('graphics/arrows.png'),
['hearts'] = love.graphics.newImage('graphics/hearts.png'),
['particle'] = love.graphics.newImage('graphics/particle.png'),
['buganimation'] = love.graphics.newImage('graphics/buganimation.png')
}
Attempting to return gTextures['buganimation'] returns a file value as normal. It's not empty.
My brain is so fried right now I can't even remember why I came to edit this. I can't remember.
Global table in Main.lua, all other functions can't access it.
print(gTextures['buganimation']) works inside the function in question. So gTextures is absolutely accessible.
Table isn't empty. AnimationSetValues is not empty.
I'm adding second answer because both are correct in context.
I ended up switching IDE's to VS Code and now the original one works.
I was originally using Eclipse LDT with a Love2D interpreter and in that environment, my original answer is correct, but in VS Code, the original is also correct.
So Dimitry was right, they are equivalent, but something about my actual Eclipse setup was not allowing that syntax to work.
I switched to VS Code after I had another strange syntax problem with the interpreter where goto syntax was not recognized and gave a persistent error. The interpreter thought goto was the name of a variable.
So I switched, and now both things are fixed. I guess I just won't use LDT for now.
Solution: Lua syntax. Brain Fry Syndrome
I wrote:
animationSetValues = {atlasarray = animationQuadArray, width = spriteWidthDivider, height = spriteHeightDivider}
Should be:
animationSetValues = {['atlasfile']=atlasfile, ['atlasarray']=animationQuadArray, ['width']=spriteWidthDivider, ['height']=spriteHeightDivider}
Edit: I'm fully aware of how to use answers. This was posted here to reserve my spot for an answer so I could edit it later when I returned back home, which is exactly what I'm doing right now. I'll keep the old post for archival purposes.
Original:
I solved it. I apologize for not posting the solution right now. My brain is melted into gravy.
I will post it tomorrow. Just wanted to "answer" saying no need to help. Solved it.
Solution is basically, "oh it's just one of those Lua things". Wonderful. I'm having so much fun with this language - you can tell by my blank expression.
From the language without line endings or brackets, but forced print parentheses... ugh. I'm going back to C# when this class is done.

In Lua, using a boolean variable from another script in the same project ends up with nill value error

This code is for a modding engine, Unitale base on Unity Written in Lua
So I am trying to use a Boolean Variable in my script poseur.lua, so when certain conditions are met so I can pass it to the other script encounter.lua, where a engine Predefined functions is being uses to make actions happens base on the occurring moment.
I tried to read the engine documentation multiple times, follow the exact syntax of Lua's fonction like GetVar(), SetVar(), SetGobal(),GetGlobal().
Searching and google thing about the Language, post on the subreddit and Game Exchange and tried to solve it by myself for hours... I just can't do it and I can't understand why ?
I will show parts of my codes for each.
poseur:
-- A basic monster script skeleton you can copy and modify for your own creations.
comments = {"Smells like the work\rof an enemy stand.",
"Nidhogg_Warrior is posing like his\rlife depends on it.",
"Nidhogg_Warrior's limbs shouldn't\rbe moving in this way."}
commands = {"GREET", "JUMP", "FLIRT", "CRINGE"}
EndDialougue = {" ! ! !","ouiii"}
sprite = "poseur" --Always PNG. Extension is added automatically.
name = "Nidhogg_Warrior"
hp = 99
atk = 1
def = 1
check = "The Nidhogg_Warrior is\rsearching for the Nidhogg"
dialogbubble = "rightlarge" -- See documentation for what bubbles you have available.
canspare = false
cancheck = true
GreetCounter = 5
Berserk = false
encounter:
-- A basic encounter script skeleton you can copy and modify for your own creations.
encountertext = "Nidhogg_Warrior is\rrunning frantically"
nextwaves = {"bullettest_chaserorb"}
wavetimer = 5.0
arenasize = {155, 130}
music = "musAncientGuardian"
enemies = {"poseur"}
require("Monsters.poseur")
enemypositions = {{0, 0}}
-- A custom list with attacks to choose from.
-- Actual selection happens in EnemyDialogueEnding().
-- Put here in case you want to use it.
possible_attacks = {"bullettest_bouncy", "bullettest_chaserorb", "bullettest_touhou"}
function EncounterStarting()
-- If you want to change the game state immediately, this is the place.
Player.lv = 20
Player.hp = 99
Player.name = "Teemies"
poseur.GetVar("Berserk")
end
Thank you for reading.
The answer to my problem was to use SetGobal(), GetGobal().
For some reasons my previous attempt to simply use SetGobal()Resulted in nil value despite writing it like that SetGobal("Berserk",true) gave me a nill value error, as soon as I launch the game.
But I still used them wrong. First I needed to put it SetGobal() at the end of the condition instead of at the start of the the poseur.lua script because the change of value... for some reasons was being overwritten by it first installment.
And to test the variable in the function in my encounter.lua, I needed to write it like that
function EnemyDialogueStarting()
-- Good location for setting monster dialogue depending on how the battle is going.
if GetGlobal("Jimmies") == true then
TEEEST()
end
end
Also any tips an suggestions are still welcome !
Well firstly, in lua simple values like bool and number are copied on assignment:
global={}
a=2
global.a=a--this is a copy
a=4--this change won't affect value in table
print(global.a)--2
print(a)--4
Secondly,
SetGobal and the other mentioned functions are not part of lua language, they must be related to your engine. Probably, they use word 'Global' not as lua 'global' but in a sense defined by engine.
Depending on the engine specifics these functions might as well do a deep copy of any variable they're given (or might as well not work with complicated objects).

Rails code segment explained

I am working on an app which has the below code:
def app
#app ||= begin
if !::File.exist? options[:config]
abort "configuration #{options[:config]} not found"
end
app, myoptions = Rack::Builder.parse_file(self.options[:config], opt_parser)
self.myoptions.merge! myoptions
app
end
end
I am struggling to get my head around several parts of it..
#app||= begin...end
Does this mean that if #app does not exist the block is run?
app ,options = rack::builder
What does the comma do to it?
Please help
Your first assumptions was correct, it does say that if #app is nil, set it to whatever is returned in the block delimited with begin, end.
Regarding the comma, it works like this:
avar, bvar = "atest", "btest"
If you look at the source for Rack:Builder.parse_file then you will notice the last line
return app, options
So it is returning two values.
Hope that helps
#Craig-Taub ansewered the question,
I just want to add some notes:
Ruby commands are expressions which means they return value and you can assign them to variables.
You can read more about expressions and statements on Wikipedia and PragProg.
Second is that when you return more than one value in a code block, Ruby will wrap it into a simple array and return it to the caller.
That's why it works like that.

How to load a file data in memory,and don't reload again. just like static field in java?

I have a function :it's load a file data and build a table.
I want to load the file only once , everytime call the function and get return table in memory,don't load file again(you know io operation repeat is bad).
the goal is just like static field in java,only build once , and use it .
how to do ?
You can do this in one of several ways. For example:
local myInternalLocal = nil
function FuncName(...)
if(not myInternalLocal) then
myInternalLocal = --Do stuff that builds the table.
end
return myInternalLocal
end
Alternatively, you can do it by replacement, which better hides the internal variable, and is (very slightly) faster:
function FuncName(...)
local myInternalLocal = --Do stuff that builds the table.
FuncName = function()
return myInternalLocal
end
end
The downside here has to do with modules. If this is inside of a module, then you may need to change how it rebinds the function. And of course, if someone stores the old function before calling it, they can keep calling the original version.
I think you want to use require to load the file.

Resources