Sass. Check If Custom Ruby Function Exists - ruby

I've written a Sass (SCSS) CSS3 #gradient mixin that also outputs a base64 encoded SVG string for IE9.
This mixin relies upon this custom ruby function be required in the user's Sass "watch" file:
require 'sass'
require 'base64'
module Sass::Script::Functions
def base64Encode(string)
assert_type string, :String
Sass::Script::String.new(Base64.encode64(string.value))
end
declare :base64Encode, :args => [:string]
end
which is called like so: base64Encode($svgStr).
However, I'd like to release my mixin library, and don't want to impose that this custom function be required.
For example, AFAIK Web Workbench for VS2012 has no way of including custom functions. If it isn't included, then I don't want to output the base64 rule.
So, is it possible to detect in the mixin whether base64Encode exists as a custom function? Otherwise, you end up with something like:
background-image: url("data:image/svg+xml;base64,base64Encode('<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"100%\" height=\"100%\" viewBox=\"0 0 1 1\" preserveAspectRatio=\"none\"><linearGradient id=\"g522\" gradientUnits=\"userSpaceOnUse\" x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\"><stop stop-color=\"white\" offset=\"0\" /><stop stop-color=\"whitesmoke\" offset=\"1\" /></linearGradient><rect x=\"0\" y=\"0\" width=\"1\" height=\"1\" fill=\"url(#g522)\" /></svg>')");
instead of
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRo PSIxMDAlIiBoZWlnaHQ9IjEwMCUiIHZpZXdCb3g9IjAgMCAxIDEiIHByZXNl cnZlQXNwZWN0UmF0aW89Im5vbmUiPjxsaW5lYXJHcmFkaWVudCBpZD0iZzUy MiIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIHgxPSIwJSIgeTE9 IjAlIiB4Mj0iMCUiIHkyPSIxMDAlIj48c3RvcCBzdG9wLWNvbG9yPSJ3aGl0 ZSIgb2Zmc2V0PSIwIiAvPjxzdG9wIHN0b3AtY29sb3I9IndoaXRlc21va2Ui IG9mZnNldD0iMSIgLz48L2xpbmVhckdyYWRpZW50PjxyZWN0IHg9IjAiIHk9 IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIGZpbGw9InVybCgjZzUyMikiIC8+ PC9zdmc+ ");
Or is possible to somehow search inside the returned string to check whether "base64Encode" is there and to ignore it?

This pull request (which has been merged) gives you a 'function-exists' function: https://github.com/nex3/sass/pull/821

Related

python-sphinx - Display only function signature with autodoc?

In Sphinx is possible to include the signature of a function or method manually using the py:function (or py:method) directive:
.. py:function:: my_func(data, named=None, *args, *kwargs)
It is also possible to use autodoc directives to include and format the whole docstring of a function or method:
.. automethod:: my_func
I am wondering if there is a way of configuring autodoc to include and format only the signature, without the rest of the docstring, so that I don't have to do it manually.
autodoc-process-signature can be used here as well.
def process_signature(app, what, name, obj, options, signature, return_annotation):
return modified_signature, modified_return_annotation
# will be rendered to method(modified_signature) -> modified_return_annotation
def setup(app):
app.connect("autodoc-process-signature", process_signature)
http://www.sphinx-doc.org/en/master/_modules/sphinx/ext/autodoc.html
See autodoc's sphinx.ext.autodoc.between.
Return a listener that either keeps, or if exclude is True excludes, lines between lines that match the marker regular expression. If no line matches, the resulting docstring would be empty, so no change will be made unless keepempty is true.
If what is a sequence of strings, only docstrings of a type in what will be processed.

Clear input field: undefined method `clear' for #<Watir::Input:XYZ> (NoMethodError)

I am not sure why I can not clear my input field.
PageObject:
element(:test_input_field) { |b| b.input(class: "search-field") }
def set_search_value(search_entry)
test_input_field.when_present.clear
test_input_field.when_present.set(search_entry)
end
Step_file:
page.set_search_value(search_entry)
Output:
undefined method `clear' for #'<'Watir::Input:0x00000003980d20'>' (NoMethodError)
The clear (and set) method are not defined for generic input elements - ie Watir::Input. They are only defined for the specific input types - text field, checkbox, etc.
To make the code work, you would need to convert the input into the more specific type, which is likely a text field. You can do this using the to_subtype method:
test_input_field.when_present.to_subtype.clear
test_input_field.when_present.to_subtype.set(search_entry)
As #SaurabhGaur mentions, set already starts by clearing the existing value, so you could just do:
test_input_field.when_present.to_subtype.set(search_entry)
Unless the input type changes, it would make more sense to define the element as a text_field so you do not need to convert it. It might depend on which page object library you are using, but I would expect you could do:
element(:test_input_field) { |b| b.text_field(class: "search-field") }
def set_search_value(search_entry)
test_input_field.when_present.clear
test_input_field.when_present.set(search_entry)
end

susy argument from sass custom function

How can I pass the return value form a custom Sass function to a Susy function?
Or is there any better approach?
This works fine:
.foo{
max-width: get_breakpoint('large');
}
But that won't:
.foo{
#include layout(get_breakpoint('large') 12);
}
Susy just falls back to the default container width instead of using the one from my get_breakpoint() function.
The built uses Compass, I have the following function in my config.rb:
module Sass::Script::Functions
#
# get breakpoint values from prefs file (json)
#
def get_breakpoint(bp)
if PROJ_PREFS['breakpoint'].include?(bp.value)
retVal = PROJ_PREFS['breakpoint'][bp.value][0].to_s+'px'
else
retVal = bp.to_s
end
Sass::Script::String.new(retVal)
end
end
Software versions: sass (3.4.21), compass (1.0.3), susy (2.2.12).
Many thanks.
It turns out that it shouldn't be a problem to use a custom function as a Susy mixin argument as long as it passes the right value. I was passing a string instead of Sass number.
Just in case someone stumble across similar problem, below there is an example of working solution retrieving breakpoint values from Json into Sass (Assuming you've got json gem installed).
Note that this solution isn't perfect from the performance point of view as it recreates the $BREAKPOINT map each time the _base.scss partial is imported. (It also omits my custom breakpoint mixin as not relevant here and which uses the breakpoint function as well)
My breakpoint definitions are stored as 'unitless' numbers in json
{
"breakpoint" : {
"mini" : [ 481 , "phablet portrait phone landscape"],
"xsmall" : [ 736 , "phablet landscape (iPhone6plus) tablet portrait"],
...
Ruby code (in Compass config.rb)
require 'json'
file = File.read(File.dirname(__FILE__)+'/preferences.json')
PROJ_PREFS = JSON.parse(file)
module Sass::Script::Functions
def get_breakpoints()
retMap = Hash.new
PROJ_PREFS['breakpoint'].each do |bp_name, bp_value|
retMap[Sass::Script::Value::String.new(bp_name.to_s)] = Sass::Script::Value::Number.new(bp_value[0],'px')
end
Sass::Script::Value::Map.new(retMap)
end
end
Sass code (e.g. _base.scss)
// create Sass map with custom function
$BREAKPOINT:get_breakpoints();
// allow Sass numbers (such as 12em, 355px) or breakpoint names (such as small, large) to be passed through
// it was just easier for me to code it in Sass (since I don't know Ruby at all)
#function breakpoint($key) {
#if not map-has-key($BREAKPOINT, $key) { #return $key; }
#return map-get($BREAKPOINT, $key);
}
Usage example (involving Susy)
.foo{
#include container(breakpoint(large));
}

Concept for recipe-based parsing of webpages needed

I'm working on a web-scraping solution that grabs totally different webpages and lets the user define rules/scripts in order to extract information from the page.
I started scraping from a single domain and build a parser based on Nokogiri.
Basically everything works fine.
I could now add a ruby class each time somebody wants to add a webpage with a different layout/style.
Instead I thought about using an approach where the user specifies elements where content is stored using xpath and storing this as a sort of recipe for this webpage.
Example: The user wants to scrape a table-structure extracting the rows using a hash (column-name => cell-content)
I was thinking about writing a ruby function for extraction of this generic table information once:
# extracts a table's rows as an array of hashes (column_name => cell content)
# html - the html-file as a string
# xpath_table - specifies the html table as xpath which hold the data to be extracted
def basic_table(html, xpath_table)
xpath_headers = "#{xpath_table}/thead/tr/th"
html_doc = Nokogiri::HTML(html)
html_doc = Nokogiri::HTML(html)
row_headers = html_doc.xpath(xpath_headers)
row_headers = row_headers.map do |column|
column.inner_text
end
row_contents = Array.new
table_rows = html_doc.xpath('#{xpath_table}/tbody/tr')
table_rows.each do |table_row|
cells = table_row.xpath('td')
cells = cells.map do |cell|
cell.inner_text
end
row_content_hash = Hash.new
cells.each_with_index do |cell_string, column_index|
row_content_hash[row_headers[column_index]] = cell_string
end
row_contents << [row_content_hash]
end
return row_contents
end
The user could now specify a website-recipe-file like this:
<basic_table xpath='//div[#id="grid"]/table[#id="displayGrid"]'
The function basic_table is referenced here, so that by parsing the website-recipe-file I would know that I can use the function basic_table to extract the content from the table referenced by the xPath.
This way the user can specify simple recipe-scripts and only has to dive into writing actual code if he needs a new way of extracting information.
The code would not change every time a new webpage needs to be parsed.
Whenever the structure of a webpage changes only the recipe-script would need to be changed.
I was thinking that someone might be able to tell me how he would approach this. Rules/rule engines pop into my mind, but I'm not sure if that really is the solution to my problem.
Somehow I have the feeling that I don't want to "invent" my own solution to handle this problem.
Does anybody have a suggestion?
J.

Ruby script for posting comments

I have been trying to write a script that may help me to comment from command line.(The sole reason why I want to do this is its vacation time here and I want to kill time).
I often visit and post on this site.So I am starting with this site only.
For example to comment on this post I used the following script
require "uri"
require 'net/http'
def comment()
response = Net::HTTP.post_form(URI.parse("http://www.geeksforgeeks.org/wp-comments-post.php"),{'author'=>"pikachu",'email'=>"saurabh8c#gmail.com",'url'=>"geekinessthecoolway.blogspot.com",'submit'=>"Have Your Say",'comment_post_ID'=>"18215",'comment_parent'=>"0",'akismet_comment_nonce'=>"70e83407c8",'bb2_screener_'=>"1330701851 117.199.148.101",'comment'=>"How can we generalize this for a n-ary tree?"})
return response.body
end
puts comment()
Obviously the values were not hardcoded but for sake of clearity and maintaining the objective of the post i am hardcoding them.
Beside the regular fields that appear on the form,the values for the hidden fields i found out from wireshark when i posted a comment the normal way.I can't figure out what I am missing?May be some js event?
Edit:
As few people suggested using mechanize I switched to python.Now my updated code looks like:
import sys
import mechanize
uri = "http://www.geeksforgeeks.org/"
request = mechanize.Request(mechanize.urljoin(uri, "archives/18215"))
response = mechanize.urlopen(request)
forms = mechanize.ParseResponse(response, backwards_compat=False)
response.close()
form=forms[0]
print form
control = form.find_control("comment")
#control=form.find_control("bb2_screener")
print control.disabled
# ...or readonly
print control.readonly
# readonly and disabled attributes can be assigned to
#control.disabled = False
form.set_all_readonly(False)
form["author"]="Bulbasaur"
form["email"]="ashKetchup#gmail.com"
form["url"]="9gag.com"
form["comment"]="Y u no put a captcha?"
form["submit"]="Have Your Say"
form["comment_post_ID"]="18215"
form["comment_parent"]="0"
form["akismet_comment_nonce"]="d48e588090"
#form["bb2_screener_"]="1330787192 117.199.144.174"
request2 = form.click()
print request2
try:
response2 = mechanize.urlopen(request2)
except mechanize.HTTPError, response2:
pass
# headers
for name, value in response2.info().items():
if name != "date":
print "%s: %s" % (name.title(), value)
print response2.read() # body
response2.close()
Now the server returns me this.On going through the html code of the original page i found out there is one more field bb2_screener that i need to fill if I want to pretend like a browser to the server.But the problem is the field is not written inside the tag so mechanize won't treat it as a field.
Assuming you have all the params correct, you're still missing the session information that the site stores in a cookie. Consider using something like mechanize, that'll deal with the cookies for you. It's also more natural in that you tell it which fields to fill in with which data. If that still doesn't work, you can always use a jackhammer like selenium, but then technically you're using a browser.

Resources