How to process Bootstrap with less.rb outside of Rails - ruby

I'm attempting to create a standalone application (independent of the Rails asset pipeline) using less.rb to output CSS files based upon Twitter Bootstrap.
The following results in an empty document
parser = Less::Parser.new :paths => [Rails.root + '/public/bootstraps/twitter-bootstrap-857b8fb/less']
tree = parser.parse("#import 'bootstrap.less'")
tree.to_css
Which results in an empty string being returned. I've tried variations of altering the #import to be the full path etc, with no success. I think I must be missing something simple.

I believe you have an issue with how you are specifying your path. As far as I can tell, Less is looking for an array of String objects, not Path obejcts.
Use the following:
parser = Less::Parser.new paths: [Rails.root.join('public', 'bootstraps', 'twitter-bootstrap-857b8fb', 'less').to_s]
tree = parser.parse("#import 'bootstrap.less'")
tree.to_css

You can simple run make as you have described here: https://github.com/twitter/bootstrap/wiki/Contributing-to-Bootstrap

If performance is not of utmost concern, you can always include less.js, which will compile the less files at runtime. Detailed instructions here.

Have you considered using the filename syntax from the less.rb github page? https://github.com/cowboyd/less.rb/
parser = Less::Parser.new :paths => ['./lib', 'other/lib'], :filename => 'mystyles.less'

Related

How do I best dump a Psych::Nodes::Document back to a YAML string?

This does what I want, but going via to_ruby seems unnecessary:
doc = Psych.parse("foo: 123")
doc.to_ruby.to_yaml
# => "---\nfoo: 123\n"
When I try to do this, I get an error:
DEV 16:49:08 >> Psych.parse("foo: 123").to_yaml
RuntimeError: expected STREAM-START
from /opt/…/lib/ruby/2.5.0/psych/visitors/emitter.rb:42:in `start_mapping'
I get the impression that the input needs to be a stream of some sort, but I don't quite get what incantation I need. Any ideas?
(The problem I'm trying to solve here, by the way (in case you know of a better way) is to fix some YAML that can't be deserialised into Ruby, because it references classes that don't exist. The YAML is quite complex, so I don't want to just search-and-replace in the YAML string. My thinking was that I could use Psych.parse to get a syntax tree, modify that tree, then dump it back into a YAML string.)
Figured out the incantation after finding the higher-level docs at https://ruby-doc.org//stdlib-2.3.0_preview1/libdoc/psych/rdoc/Psych/Nodes.html, though please let me know if there's a better way:
doc = Psych.parse("foo: 123")
stream = Psych::Nodes::Stream.new
stream.children << doc
stream.to_yaml
# => "foo: 123\n"

Regex in Ruby for a URL that is an image

So I'm working on a crawler to get a bunch of images on a page that are saved as links. The relevant code, at the moment, is:
def parse_html(html)
html_doc = Nokogiri::HTML(html)
nodes = html_doc.xpath("//a[#href]")
nodes.inject([]) do |uris, node|
uris << node.attr('href').strip
end.uniq
end
I am current getting a bunch of links, most of which are images, but not all. I want to narrow down the links before downloading with a regex. So far, I haven't been able to come up with a Ruby-Friendly regex for the job. The best I have is:
^https?:\/\/(?:[a-z0-9\-]+\.)+[a-z]{2,6}(?:/[^\/?]+)+\.(?:jpg|gif|png)$.match(nodes)
Admittedly, I got that regex from someone else, and tried to edit it to work and I'm failing. One of the big problems I'm having is the original Regex I took had a few "#"'s in it, which I don't know if that is a character I can escape, or if Ruby is just going to stop reading at that point. Help much appreciated.
I would consider modifying your XPath to include your logic. For example, if you only wanted the a elements that contained an img you can use the following:
"//a[img][#href]"
Or even go further and extract just the URIs directly from the href values:
uris = html_doc.xpath("//a[img]/#href").map(&:value)
As some have said, you may not want to use Regex for this, but if you're determined to:
^http(s?):\/\/.*\.(jpeg|jpg|gif|png)
Is a pretty simple one that will grab anything beginning with http or https and ending with one of the file extensions listed. You should be able to figure out how to extend this one, Rubular.com is good for experimenting with these.
Regexp is a very powerful tool but - compared to simple string comparisons - they are pretty slow.
For your simple example, I would suggest using a simple condition like:
IMAGE_EXTS = %w[gif jpg png]
if IMAGE_EXTS.any? { |ext| uri.end_with?(ext) }
# ...
In the context of your question, you might want to change your method to:
IMAGE_EXTS = %w[gif jpg png]
def parse_html(html)
uris = []
Nokogiri::HTML(html).xpath("//a[#href]").each do |node|
uri = node.attr('href').strip
uris << uri if IMAGE_EXTS.any? { |ext| uri.end_with?(ext) }
end
uris.uniq
end

Using Nokogiri to validate XML: finding the line-nr of validation errors?

I am trying to validate pretty large XML files against a XSD-schema. Nokogiri does this perfectly fine, using the following code:
xsd = Nokogiri::XML::Schema(File.read('batch_schema.xsd'))
doc = Nokogiri::XML(File.read('batch205.xml'))
xsd.validate(doc).each do |error|
puts "#{error.line} :: #{error.message}"
end
Simple enough. Only: error.line is always 65535. Because the XML files we need to check are really huge, it would be really, really, helpful to get the line-numbers.
I found this XSD Validation cheatsheet so that is where I found the option to read the line.
In the libxml2 documentation I found I have to enable line-numbers for it to be set. Any idea how to enable line-numbers with Nokogiri or get a line-number in a validation-error?
I just had to write it a little differently, instead of loading and parsing the entire xml upfront, I just needed to validate the file itself. Like so:
xsd = Nokogiri::XML::Schema(File.read('batch_schema.xsd'))
xsd.validate('batch205.xml').each do |error|
puts "#{error.line} :: #{error.message}"
end

How to build an Object from XML, modify, then write to File in Ruby

I'm having an awful time trying to use a library to parse an XML File into a hash like object, modify it, then print it back out to another XML file in Ruby. For a class I'm taking, we're supposed to use a Java JAXB like library where we convert XML into an object. We've already done SAX and DOM methods so we can't use those methods of XML de-serialization. Nokogiri helped me with both of these in Ruby.
The only problem is that besides the SIMPLE modifications I'm making to the objects, when I write to file it has drastic differences. Is there a Ruby library meant for doing just this? I've tried: ROXML, XML::Mapping, and ActiveSupport::CoreExt. The only one I can get to even run is ActiveSupport, and even then it starts putting element attributes as child elements in the output XML.
I'm willing to try out XmlSimple, but I'm curious has anyone actually had to do this before/run into the same problems? Again, I can't read in lines one at a time like SAX or build a Tree like structure like DOM, it needs to be a hash like object.
Any help is much appreciated!
You should have a look into nokogiri: http://nokogiri.org/
Then you can parse the XML like this :
xml_file = "some_path"
#xml = Nokogiri::XML(File.open xml_file)
#xml.xpath('//listing').each do |node|
style = node.search("style").text
end
With Xpath, you can perform queries in the XML :
#xml.xpath("//listing[name='John']").first(10)
OK, I got it working. After looking at ActiveSupport::CoreExt 's source code I found it just uses a gem called xml-simple. What's obnoxious is the gem, library name in the require statement, and class name are a mixture of hyphenated and non hyphenated spellings. For future reference here's what I did:
# gem install xml-simple
# ^ all lowercase, hyphenated
require 'xmlsimple'
# ^ all lowercase, not hyphenated
doc = XmlSimple.xml_in 'hw3.xml', 'KeepRoot' => true
# ^ Camel cased (it's a class), not hyphenated
# doc.class => Hash
# manipulate doc as a hash
file = File.new('HW3a.xml', 'w')
file.write("<?xml version='1.0' encoding='utf-8'?>\n")
file.write(XmlSimple.xml_out doc, 'KeepRoot' => true)
I hope this helps someone. Also make sure you pay attention to case and hyphens with this gem!!!

GridFS in Ruby: How to upsert?

Does GridFS have an upsert?
For example, if i want to save an image with a specified _id, and one with that same _id already exists, i want it to overwrite (update) it. Otherwise, insert it.
The spec isn't really designed to support upserts, since you're technically modifying more than one document, and certainly tricky race conditions can arise. So we recommend what Matt has done, which is to delete first and then put.
I looked at the mongo ruby gem source code and found this:
# Store a file in the file store. This method is designed only for writing new files;
# if you need to update a given file, first delete it using #Grid#delete.
# ...
def put(data, opts={})
So, I did this in the code:
grid.delete(id) # if exists
grid.put(tmp_file.read, :_id => id, :content_type => file_type)
See the working sinatra script here:
http://github.com/acani/acani-sinatra/blob/master/acani.rb#L97

Resources