unrestrictedTraverse gets the wrong object when there is two adjacent identical ids - plone

I have:
try:
path1 = /Plone/s/a
path2 = 2011/07/07
#The path to traverse becomes /Plone/s/a/2011/07/07/. From
#Plone to last 07, they are normal Folders.
ob = self.portal.unrestrictedTraverse('%s/%s/' % (path1, path2))
print ob
except AtributeError:
#do something
pass
/Plone/s/a/2011/07/07/ doesn't exist. /Plone/s/a/2011/07/ exists. The code above is supposed to give an AtributeError, but I get /Plone/s/a/2011/07/ object instead. It prints:
<ATFolder at /Plone/s/a/2011/07 used for /Plone/s/a/2011/07>
I don't want to get a "similar" result from the traverse, this is wrong. I need specifically /Plone/s/a/2011/07/07/. If it doesn't exists, I want to catch the exception .
Which other approaches can I use to see if there's an object exactly at /Plone/s/a/2011/07/07/, and not close enough like /Plone/s/a/2011/07/?

You hit acquisition.
You want to get the '07' element/property/attribute of the '07' folder. But this last one doesn't have a sub-object with that id. So , due to acquisition, the existing '07' folder asks to its parent element if it has a sub-object with the mentioned id, and of course, '2011' folder has that element, the '07' one you are sitting on.
This is a rough explanation of how acquisition works.
Another example is this URL:
http://plone.org/news/news/news/news/news/events
The 'events' folder doesn't really live in 'news' folder. And all those 'news' folders aren't really there, but there is at least one 'news' folder living in plone.org root, and although it doesn't have an 'events' folder, its parent (plone.org again) does.
Here you have some references:
http://plone.org/documentation/glossary/acquisition
http://docs.zope.org/zope2/zope2book/Acquisition.html
If you want to make sure an element/property/attribute is really part of the parent element you should use aq_base from Acquisition:
from Acquisition import aq_base
plone = aq_base(self.portal.Plone)
s = aq_base(getattr(plone, 's'))
a = aq_base(getattr(s, 'a'))
year = aq_base(getattr(a, '2011'))
month = aq_base(getattr(year, '07'))
day = aq_base(getattr(month, '07'))
aq_base strips the acquisition chain from the element so no acquisition will be used to get its elements.

Related

Get Next and Previous Tags (AwesomeWM)

Is there a way to get the next or previous tag in AwesomeWM Lua Config?
Reason :- I want to get the next or previous tag to set the focused clients tag to it and then move to the tag.
I know there is awful.tag.viewnext which moves to the next tag but unsure about how to get the tag it will move to to set this on a client.
Thanks in advance
Well... yes, there is a way, but there is not a completely trivial one.
First, let's look at the default config. What existing functionality has to get next/previous tags? That is the mouse wheel on the taglist:
https://github.com/awesomeWM/awesome/blob/7a759432d3100ff6870e0b2b427e3352bf17c7cc/awesomerc.lua#L160-L161
So, how does awful.tag.viewnext and viewprev get the next tag? These functions just call viewidx with an idx of 1 or -1, e.g.:
https://github.com/awesomeWM/awesome/blob/7a759432d3100ff6870e0b2b427e3352bf17c7cc/lib/awful/tag.lua#L1494
So, awful.tag.viewidx can do what we want. How does it do it?
It gets a table of all un-hidden tags, finds the index of the currently selected tag and then uses gears.math.cycle to compute the index of the tag with the requested offset.
https://github.com/awesomeWM/awesome/blob/7a759432d3100ff6870e0b2b427e3352bf17c7cc/lib/awful/tag.lua#L1452-L1469
For you, something like the following should do the trick:
function get_tag_at_offset(i, s)
s = screen[s or awful.screen.focused()]
local tags = s.tags
local showntags = {}
for _, t in pairs(tags) do
if not awful.tag.getproperty(t, "hide") then
table.insert(showntags, t)
end
end
for k, t in ipairs(showntags) do
if t == sel then
return showntags[gears.math.cycle(#showntags, k + i)]
end
end
end
The above function can be used like get_tag_at_offset(1) to get the next tag and with argument -1 for the previous. Where possible, I would recommend to also pass in a screen via the second argument.
Also, all of this is completely untested and just written on the spot. There could very well be typos and other mistakes in here.

Nokogiri and isolating select elements from an array full of Nokogiri nodes

I'm trying to scrape http://www.ign.com/games/reviews using Nokogiri and I'd like to instantiate new review objects that correspond to each game review on the page. Naturally, I'd also like to grab each numeric Score from each review and assign that score value as a class attribute to my review objects.
The problem is, the best I can do is return an entire string of scores mushed together instead of a list consisting of each score.
class VideoGameReviews::Review
attr_accessor :name, :score, :url
def self.scrape_titles
#doc = Nokogiri::HTML(open("http://www.ign.com/games/reviews?"))
#doc.search("#item-list div.itemList div.itemList-item").each do |review|
new_review = VideoGameReviews::Review.new
new_review.score = review.search("span.scoreBox-score").text
=> "99996.37.17.17.17778.58.58.586.36.47.187.57.88.95.587.6" #Not what I want
end
end
end
Any advice on how to extract a list of scores with each score separate and unique from other scores? Maybe use a more specific CSS selector?
You are using nokogiri properly but need to revise your logic to store the scores properly. For instance, we can get the score for an individual game pretty easily:
new_review.score = fourth_item.search("span.scoreBox-score").text
=> "6.3"
Instead of having to do everything in a single method, you can start by breaking your code into smaller methods and cacheing values as needed. I would change this class name as well since your Review class both represents a Review item and also scrapes (violation of Single Responsibility Principle). Maybe something like the following would be better?
require ‘nokogiri’
class VideoGameReviews::ReviewScraper
def reviews
#reviews ||= Nokogiri::HTML(open("http://www.ign.com/games/reviews?"))
end
def review_items
#review_items ||= reviews.search("#item-list div.itemList div.itemList-item")
end
def store_reviews
review_items.each do |review|
new_review = VideoGameReviews::Review.new #Review class still used to save review
new_review.score = review.search("span.scoreBox-score").text
#get other data
new_review.save! #or however you plan on persisting the data
end
end
end
The question will be: how will you save the reviews (in local memory, in a db, etc)? For something quick, ActiveRecord is pretty simple (and you use it independently from Rails).
Note that the :each method in Ruby will always return the original collection on which it's called. so for instance the following will return [1,2]:
[1,2].each do |n|
n * 4
end

Meteor - Passing a jade helper into a helper function

I'm trying to populate a list with a dataset and set the selected option with a helper function that compares the current data with another object's data (the 2 objects are linked)
I made the same type of list population with static variables:
Jade-
select(name='status')
option(value='Newly Acquired' selected='{{isCurrentState "Newly Acquired"}}') Newly Acquired
option(value='Currently In Use' selected='{{isCurrentState "Currently In Use"}}') Currently In Use
option(value='Not In Use' selected='{{isCurrentState "Not In Use"}}') Not In Use
option(value='In Storage' selected='{{isCurrentState "In Storage"}}') In Storage
Coffeescript-
"isCurrentState" : (state) ->
return #status == state
This uses a helper isCurrentState to match a given parameter to the same object that my other code is linked to so I know that part works
The code I'm trying to get to work is :
Jade-
select.loca(name='location')
each locations
option(value='#{siteName}' selected='{{isCurrentLocation {{siteName}} }}') #{siteName}
Coffeescript-
"isCurrentLocation": (location) ->
return #locate == location
All the other parts are functioning 100%, but the selected part is not
I've also tried changing the way I entered the selected='' part in a manner of ways such as:
selected='{{isCurrentLocation "#{siteName}" }}'
selected='{{isCurrentLocation "#{siteName} }}'
selected='{{isCurrentLocation {{siteName}} }}'
selected='#{isCurrentLocation "{{siteName}}" }'
selected='#{isCurrentLocation {{siteName}} }'
selected='#{isCurrentLocation #{siteName} }'
Is what I'm trying to do even possible?
Is there a better way of achieving this?
Any help would be greatly appreciated
UPDATE:
Thanks #david-weldon for the quick reply, i've tried this out a bit and realised that I wasn't exactly clear in what I was trying to accomplish in my question.
I have a template "update_building" created with a parameter( a buidling object) with a number of attributes, one of which is "locate".
Locations is another object with a number of attributes as well, one of which is "siteName". One of the siteName == locate and thus i need to pass in the siteName from locations to match it to the current building's locate attribute
Though it doesn't work in the context I want to use it definitely pointed me in a direction I didn't think of. I am looking into moving the parent template(The building) date context as a parameter into the locations template and using it from within the locations template. This is easily fixable in normal HTML spacebars with:
{{>locations parentDataContext/variable}}
Something like that in jade would easily solve this
Short answer
selected='{{isCurrentLocation siteName}}'
Long answer
You don't really need to pass the current location because the helper should know it's own context. Here's a simple (tested) example:
jade
template(name='myTemplate')
select.location(name='location')
each locations
option(value=this selected=isCurrentLocation) #{this}
coffee
LOCATIONS = [
'Newly Acquired'
'Currently In Use'
'Not In Use'
'In Storage'
]
Template.myTemplate.helpers
locations: LOCATIONS
isCurrentLocation: ->
#toString() is Template.instance().location.get()
Template.myTemplate.onCreated ->
#location = new ReactiveVar LOCATIONS[1]
I looked into the datacontexts some more and ended up making the options that populate the select into a different template and giving that template a helper, accessing the template's parent's data context and using that to determine which location the building had saved in it so that I could set that option to selected
Jade-
template(name="location_building_option")
option(value='#{siteName}' selected='{{isSelected}}') #{siteName}
Coffeescript -
Template.location_building_option.helpers
'isSelected': ->
parent = Template.parentData(1)
buildSite = parent.locate
return #siteName == buildSite
Thanks #david-weldon, Your answer helped me immensely to head in the right direction

A simple AMZI prolog recursion, but is not giving the correct result as expected

So this is my .pro file content (AMZI PROLOG) :
room(kitchen).
room(office).
room(hall).
room('dining room').
room(cellar).
door(office, hall).
door(kitchen, office).
door(hall, 'dining room').
door(kitchen, cellar).
door('dining room', kitchen).
location(desk,office).
location(apple,kitchen).
location(flashlight,desk).
location('washing machine',cellar).
location(nani,'washing machine').
location(broccoli,kitchen).
location(crackers,kitchen).
location(computer,office).
location(envelope,desk).
location(stamp,envelope).
location(key,envelope).
edible(apple).
edible(crackers).
tastes_yucky(broccoli).
here(kitchen).
is_located_in(T1,T2):-location(X,T2),is_located_in(T1,X).
What I want to achieve is that if I use, for example, is_located_in(X,office), then the result will be :
X=desk,
X=flashlight,
X=computer,
X=envelope,
X=stamp,
X=key,
no
(in no particular order).
That way, the result will include things that basically located in / on the object in the office, instead of things that located directly in the office.
This is the source : http://www.amzi.com/AdventureInProlog/a8recurs.php
There is stated that the code are fine, but when I test it, it just returned :
no
Please help. Thanks.
Try this (in this order):
is_located_in(T1,T2):-location(T1,T2).
is_located_in(T1,T2):-location(X,T2),is_located_in(T1,X).

Automatically create new objects in a Plone Folder, being the ids only sequential numbers

I have the following structure:
/Plone/folder/year/month/day/id
I want to create the last id sequentially in a tool using invokeFactory. I want to have:
/Plone/folder/2011/06/21/1
/Plone/folder/2011/06/21/2
/Plone/folder/2011/06/21/3
/Plone/folder/2011/06/21/4
Instead of:
/Plone/folder/2011/06/21/id-1
/Plone/folder/2011/06/21/id-2
/Plone/folder/2011/06/21/id-3
/Plone/folder/2011/06/21/id-4
...that is automatically done when I try to create an object with the same name in a folder, Plone handles that for me adding a sequential number. I want an efficient way to create objects, but only using a sequential number instead of a name with a sequential number. I can do that getting the total number os items in a folder, but would like to know if there's a better way.
Real life example: http://plone.org/products/collective.captcha/issues/4
If you're creating these objects manually, you can do something like:
brains = context.getFolderContents({'sort_on' : 'id', 'sort_order' : "reverse"})
if len(brains) > 0:
id = str(int(brains[0].id) + 1)
else:
id = '1'
Then you'll have to create the object manually with that id.
If you want this to do done automatically for you when a user creates content, you might want to look into creating a content rule to change the id of the content for you. An example that might help is collective.contentrules.yearmonth

Resources