Exclude files from FileList on Ruby - ruby

i have a rakefile with the following SRC = FileList['md/*.md'] but i want to exclude some files
I have tried
SRC = FileList['md/*.md'].exclude("md/header.md")
SRC = FileList['md/*.md'].exclude(/header/)
SRC = FileList['md/*.md'].exclude(/header.md$/)
But it doesn't work, always list me all files
a example:
in place of my rakefile.rb, I have a directory md with the following contents:
rakefile.rb
md/
index.md
example.md
header.md
I want to list all without header.md

This works fine for me:
p FileList['md/*.md']
#=> ["md/example.md", "md/header.md", "md/index.md"]
p FileList['md/*.md'].exclude("md/header.md")
#=> ["md/example.md", "md/index.md"]
p FileList['md/*.md'].exclude(/header/)
#=> ["md/example.md", "md/index.md"]
p FileList['md/*.md'].exclude(/header.md$/)
#=> ["md/example.md", "md/index.md"]

Not sure what's going on. Perhaps it's the version of Rake and/or ruby that you're using?
I've tested your snippets with ruby-1.8.7 (rake 0.8.7 and rake 0.9.2.2) and with ruby-1.9.2 (rake 0.8.7 and rake 0.9.2.2). All four configurations give the expected output.
Code:
puts "no exculde:"
puts FileList['md/*.md']
puts '---'
puts "exclude('md/header.md'):"
puts FileList['md/*.md'].exclude('md/header.md')
puts '----'
puts "exclude(/header/):"
puts FileList['md/*.md'].exclude(/header/)
puts '----'
puts "exclude(/header.md$/):"
puts FileList['md/*.md'].exclude(/header.md$/)
Output:
no exculde:
md/example.md
md/header.md
md/index.md
---
exclude('md/header.md'):
md/example.md
md/index.md
----
exclude(/header/):
md/example.md
md/index.md
----
exclude(/header.md$/):
md/example.md
md/index.md

Related

Sample ''Hola'" Rubygem push error on windows

I am following the very basic tutorial found here: http://guides.rubygems.org/make-your-own-gem/
hola_username.rb:
class Hola
def self.hi
puts "Hello world!"
end
end
hola_username.gemspec:
Gem::Specification.new do |s|
s.name = 'hola_username'
s.version = '0.0.0'
s.date = '2010-04-28'
s.summary = "Hola!"
s.description = "A simple hello world gem"
s.authors = ["Surname Lastname"]
s.email = 'me.me#gmail.com'
s.files = ["lib/hola_username.rb"]
s.homepage =
'http://rubygems.org/gems/hola_username'
s.license = 'MIT'
end
That really is all there is to the project.
I can build my gem with
gem build .\hola_username.gemspec
I have also tested it by importing and executing the hi function of the Hola class and it works:
PS E:\hola_username> gem install .\hola_username-0.0.0.gem
Successfully installed hola_username-0.0.0
Parsing documentation for hola_username-0.0.0
Done installing documentation for hola_username after 0 seconds
1 gem installed
&
irb(main):001:0> require 'hola_username'
=> true
irb(main):002:0> Hola.hi
Hello world!
=> nil
irb(main):003:0>
But when I try to
gem push .\hola_username-0.0.0.gem
I get:
ERROR: While executing gem ... (Psych::SyntaxError)
(): control characters are not allowed at line 1 column 1
Any ideas?
Edit: I am on a windows 10 machine using ruby 2.0.0p598
Edit v01: Anything I put after gem push will result in the above error, doesn't seem to be a problem with the sample rubygem.
Edit v02: My credentials file that was generated in the .gem folder however stars with hex characters: fffe2d002d00.. Which might be the ones causing trouble?
My credentials file in .gem folder was encoded with UCS2 - Little Endian and converting it to UTF without BOM did the trick.
Although I have absolutey no idea why..

RUBY (Errno::ENOENT), no such file or directory # dir_s_mkdir

I'm following "The Bastards Book of Ruby" and I am trying to build a webscraper using nokogiri but about a quarter of the way into it when I attempt to run the code it throws the error:
Crawler.rb:6:in `mkdir': No such file or directory # dir_s_mkdir - data-hold/nobel (Errno::ENOENT)
from Crawler.rb:6:in `<main>'
My code is as follows:
require 'rubygems'
require 'nokogiri'
require 'open-uri'
DATA_DIR = "data-hold/nobel"
Dir.mkdir(DATA_DIR) unless File.exists?(DATA_DIR)
BASE_WIKIPEDIA_URL = "http://en.wikipedia.org"
LIST_URL = "#{BASE_WIKIPEDIA_URL}/wiki/List_of_Nobel_laureates"
HEADERS_HASH = {"User-Agent" => "Ruby/#{RUBY_VERSION}"}
page = Nokogiri::HTML(open(LIST_URL))
rows = page.css('div.mw-content-ltr table.wikitable tr')
rows[1..-2].each do |row|
hrefs = row.css("td a").map{ |a|
a['href'] if a['href'] =~ /^\/wiki\//
}.compact.uniq
hrefs.each do |href|
remote_url = BASE_WIKIPEDIA_URL + href
local_fname = "#{DATA_DIR}/#{File.basename(href)}.html"
unless File.exists?(local_fname)
puts "Fetching #{remote_url}..."
begin
wiki_content = open(remote_url, HEADERS_HASH).read
rescue Exception=>e
puts "Error: #{e}"
sleep 5
else
File.open(local_fname, 'w'){|file| file.write(wiki_content)}
puts "\t...Success, saved to #{local_fname}"
ensure
sleep 1.0 + rand
end # done: begin/rescue
end # done: unless File.exists?
end # done: hrefs.each
end # done: rows.each
I have literally no idea why it is not creating a new directory to store the data in. I know I must be missing something extremely simple...
My best guess is that not only does "data-hold/nobel" not exist, "data-hold/" does not exist either. Since mkdir does not recursively create all parent directories of the directory you want to create, an error is thrown.
To fix this, you could use FileUtils.mkdir_p, which does create all parent directories.
Be sure to include fileutils before using mkdir_p.
Bundled the requirements into a method with the proper debug message. Works as expected.
$:~/rubyterminals/file_tansfer$ cat mkdir_mthod.rb
#!/usr/bin/env ruby
require 'fileutils'
def run
my_dir="/home/rubyterminals/file_tansfer/new_dir"
create_a_directory(my_dir)
end
def create_a_directory(dir_name)
if dir_name
# dir_name was specified, ensure it is created and writable.
unless File.exist?(dir_name)
begin
FileUtils.mkdir_p(dir_name)
puts "just made the following dir #{dir_name}"
rescue Errno::EACCES => e
abort "Failed to create #{dir_name}: #{e.message}"
end
end
end
end
run
tested it :
-SVE1411EGXB:~/rubyterminals/file_tansfer$ ./mkdir_mthod.rb
just made the following dir /home/rubyterminals/file_tansfer/new_dir
Hope this help.

Dynamically find which file is including the current file in Ruby

Context
I am auto-requiring all files in a directory structure via
# base.rb
dir = File.dirname(__FILE__)
path = File.join(dir, '**', '*.rb')
Dir[path].each { |file| require File.expand_path(file, __FILE__) }
and am calling this snippet through a require statement in a separate file, api.rb.
Problem
This code snippet includes itself (base.rb) as well as api.rb.
Question
Is there a 'clean' way to do this type of auto-requiring while dynamically avoiding including the file that has called the auto-require'er (i.e. api.rb)?
Remember that when you require a file identified by a certain path more than once each subsequent call to require will return false and the file won't be reevaluated. As a result if your base.rb, which requires everything else, is itself required, further attepts to require it should not lead to a reevaluation.
Let's demonstrate it using an example. Create a lib directory with 3 files inside.
# lib/a.rb
require 'base'
puts :a
# lib/b.rb
require 'base'
puts :b
# lib/base.rb
$counter ||= 0
puts "Evaluated base.rb #{$counter += 1} times"
dir = File.dirname(__FILE__)
path = File.join(dir, '**', '*.rb')
Dir[path].each { |file| require File.expand_path file }
Execute lib/base.rb directly. base.rb will be evaluated twice: firstly, when it's executed directly; secondly, when it's required by a.rb. Notice, that it is not evaluated when it's required from b.rb.
$ ruby -I lib lib/base.rb
Evaluated base.rb 1 times
Evaluated base.rb 2 times
a
b
Compare with requireing it. Now base.rb is evaluated once only, because attempts to require it in a.rb and b.rb were preceded by having the file required using the command line -r switch.
$ ruby -I lib -r base -e 'puts :ok'
Evaluated base.rb 1 times
a
b
ok
Kernel.caller
returns the current execution stack as an array of strings. You can avoid
calling require on filenames which you find in that array. Multiple files with
the same basename would trip this up. I don't see a way to get a more precise
list of ancestor files.
$ head *.rb
==> A.rb <==
require 'base'
puts :A
==> B.rb <==
require 'base'
puts :B
==> CA.rb <==
require 'base'
puts :CA
==> base.rb <==
dir = File.dirname(__FILE__)
path = File.join(dir, '**', '*.rb')
required = caller.map { |frame| /^(.+):\d+:in `require'$/.match(frame) and File.basename $1 }.compact
Dir[path].each { |file| required.include?(File.basename file) or require File.expand_path file }
$ ruby A.rb
B
CA
A
$ ruby B.rb
A
CA
B
$ ruby CA.rb
A
B
CA
$ ruby base.rb
B
CA
A
$

List of installed gems?

Is there a Ruby method I can call to get the list of installed gems?
I want to parse the output of gem list.
Is there a different way to do this?
This lists all the gems I have installed.
gem query --local
http://guides.rubygems.org/command-reference/#gem-list
Listing all installed gems
The Gem command is included with Ruby 1.9+ now, and is a standard addition to Ruby pre-1.9.
require 'rubygems'
name = /^/i
dep = Gem::Dependency.new(name, Gem::Requirement.default)
specs = Gem.source_index.search(dep)
puts specs[0..5].map{ |s| "#{s.name} #{s.version}" }
# >> Platform 0.4.0
# >> abstract 1.0.0
# >> actionmailer 3.0.5
# >> actionpack 3.0.5
# >> activemodel 3.0.5
# >> activerecord 3.0.5
Here's an updated way to get a list:
require 'rubygems'
def local_gems
Gem::Specification.sort_by{ |g| [g.name.downcase, g.version] }.group_by{ |g| g.name }
end
Because local_gems relies on group_by, it returns a hash of the gems, where the key is the gem's name, and the value is an array of the gem specifications. The value is an array of the instances of that gem that is installed, sorted by the version number.
That makes it possible to do things like:
my_local_gems = local_gems()
my_local_gems['actionmailer']
# => [Gem::Specification.new do |s|
# s.authors = ["David Heinemeier Hansson"]
# s.date = Time.utc(2013, 12, 3)
# s.dependencies = [Gem::Dependency.new("actionpack",
# Gem::Requirement.new(["= 4.0.2"]),
# :runtime),
# Gem::Dependency.new("mail",
# Gem::Requirement.new(["~> 2.5.4"]),
# :runtime)]
# s.description = "Email on Rails. Compose, deliver, receive, and test emails using the familiar controller/view pattern. First-class support for multipart email and attachments."
# s.email = "david#loudthinking.com"
# s.homepage = "http://www.rubyonrails.org"
# s.licenses = ["MIT"]
# s.name = "actionmailer"
# s.require_paths = ["lib"]
# s.required_ruby_version = Gem::Requirement.new([">= 1.9.3"])
# s.requirements = ["none"]
# s.rubygems_version = "2.0.14"
# s.specification_version = 4
# s.summary = "Email composition, delivery, and receiving framework (part of Rails)."
# s.version = Gem::Version.new("4.0.2")
# end]
And:
puts my_local_gems.map{ |name, specs|
[
name,
specs.map{ |spec| spec.version.to_s }.join(',')
].join(' ')
}
# >> actionmailer 4.0.2
...
# >> arel 4.0.1,5.0.0
...
# >> ZenTest 4.9.5
# >> zucker 13.1
The last example is similar to the gem query --local command-line, only you have access to all the information for a particular gem's specification.
Both
gem query --local
and
ruby -S gem list --local
list 69 entries
While
ruby -e 'puts Gem::Specification.all_names'
return 82
I used wc -l to get the numbers. Not sure if that is the right way to check. Tried to redirect the output to text files and diffed but that didn't help - will need to compare manually one by one.
There's been a method for this for ages:
ruby -e 'puts Gem::Specification.all_names'
Gem::Specification.map {|a| a.name}
However, if your app uses Bundler it will return only list of dependent local gems. To get all installed:
def all_installed_gems
Gem::Specification.all = nil
all = Gem::Specification.map{|a| a.name}
Gem::Specification.reset
all
end
use this code (in console mode):
Gem::Specification.all_names
Here's a really nice one-liner to print all the Gems along with their version, homepage, and description:
Gem::Specification.sort{|a,b| a.name <=> b.name}.map {|a| puts "#{a.name} (#{a.version})"; puts "-" * 50; puts a.homepage; puts a.description; puts "\n\n"};nil
A more modern version would be to use something akin to the following...
require 'rubygems'
puts Gem::Specification.all().map{|g| [g.name, g.version.to_s].join('-') }
NOTE: very similar the first part of an answer by Evgeny... but due to page formatting, it's easy to miss.
Try it in the terminal:
ruby -S gem list --local
Maybe you can get the files (gems) from the gems directory?
gemsdir = "gems directory"
gems = Dir.new(gemsdir).entries
From within your debugger type $LOAD_PATH to get a list of your gems. If you don't have a debugger, install pry:
gem install pry
pry
Pry(main)> $LOAD_PATH
This will output an array of your installed gems.

Using rubyzip to add files and nested directories to a zipoutputstream

I'm struggling with getting rubyzip to append directories to a zipoutputstream. (I want the output stream so I can send it from a rails controller). My code follows this example:
http://info.michael-simons.eu/2008/01/21/using-rubyzip-to-create-zip-files-on-the-fly/
When modified to include directories in the list of files to add I get the following error:
Any help would be greatly appreciated.
UPDATE
After trying a number of solutions I had best success with zipruby which has a clean api and good examples: http://zipruby.rubyforge.org/.
Zip::ZipFile.open(path, Zip::ZipFile::CREATE) do |zip|
songs.each do |song|
zip.add "record/#{song.title.parameterize}.mp3", song.file.to_file.path
end
end
OOOOOuuuhh...you DEFINITELY want ZIPPY. It's a Rails plugin that abstracts a lot of the complexity in rubyzip, and lets you create what you're talking about, including directories (from what I recall).
Here you go:
http://github.com/toretore/zippy
And direct from the zippy site:
Example controller:
def show
#gallery = Gallery.find(params[:id])
respond_to do |format|
format.html
format.zip
end
end
Example view:
zip['description.txt'] = #gallery.description
#gallery.photos.each do |photo|
zip["photo_#{photo.id}.png"] = File.open(photo.url)
end
edit: Amending per user comment:
Hmm...the whole objective of using Zippy is to make it a whole lot easier to use ruby zip.
Ya might want to take a second (or first) look...
Here's how to make a directory with directories:
some_var = Zippy.open('awsum.zip') do |zip|
%w{dir_a dir_b dir_c diri}.each do |dir|
zip["bin/#{dir}/"]
end
end
...
send_file some_var, :file_name => ...
Zippy will work for this. There may be a more cool way to do this but since there are essentially no docs, here's what I came up with for recursively copying directories with Zippy in a Rakefile. This Rakefile is used in a Rails environment so I put gem requirements in my Gemfile:
#Gemfile
source 'http://rubygems.org'
gem 'rails'
gem 'zippy'
And this is the Rakefile
#Rakefile
def add_file( zippyfile, dst_dir, f )
zippyfile["#{dst_dir}/#{f}"] = File.open(f)
end
def add_dir( zippyfile, dst_dir, d )
glob = "#{d}/**/*"
FileList.new( glob ).each { |f|
if (File.file?(f))
add_file zippyfile, dst_dir, f
end
}
end
task :myzip do
Zippy.create 'my.zip' do |z|
add_dir z, 'my', 'app'
add_dir z, 'my', 'config'
#...
add_file z, 'my', 'config.ru'
add_file z, 'my', 'Gemfile'
#...
end
end
Now I can use it like this:
C:\> cd my
C:\my> rake myzip
and it will produce my.zip which contains an inner directory called 'my' with copies of selected files and directories.
I was able to get directories working with the same ZipOutputStream used in the original article.
All I had to do was add the directory when calling zos.put_next_entry.
For example:
require 'zip/zip'
require 'zip/zipfilesystem'
t = Tempfile.new("some-weird-temp-file-basename-#{request.remote_ip}")
# Give the path of the temp file to the zip outputstream, it won't try to open it as an archive.
Zip::ZipOutputStream.open(t.path) do |zos|
some_file_list.each do |file|
# Create a new entry with some arbitrary name
zos.put_next_entry("myfolder/some-funny-name.jpg") # Added myfolder/
# Add the contents of the file, don't read the stuff linewise if its binary, instead use direct IO
zos.print IO.read(file.path)
end
end
# End of the block automatically closes the file.
# Send it using the right mime type, with a download window and some nice file name.
send_file t.path, :type => 'application/zip', :disposition => 'attachment', :filename => "some-brilliant-file-name.zip"
# The temp file will be deleted some time...
t.close
I just changed zos.put_next_entry('some-funny-name.jpg') to zos.put_next_entry('myfolder/some-funny-name.jpg'), and the resulting zipfile had a nested folder called myfolder that contained the files.

Resources