include files recursively in Cocoapods podspec - cocoapods

I want to create a local podspec that is based on some private code. I can't seem to use the 'source' attribute, as that is not working. I can use the 'source_files' attribute, but it does not include files recursively. So with a directory that looks like this
Library
/src
/Core
/Audio
/Graphics
And my podspec looks like this:
Pod::Spec.new do |s|
...
s.source = 'src' # this does not work.
s.source_files = 'src' # this only includes the files in src, and not in any of the Core, Audio or Graphics folders.
I kind of want to specify a '-r' flag. I have tried using wildcards but no luck.

The source_files attribute uses Ruby file glob syntax. The pattern must be relative to the root of your project (i.e., the podspec file), so this should work for you:
s.source_files = 'Library/src/**/*.{h,m}'
The source attribute is not for source code files, but rather for the remote repository from which the code should be retrieved (most commonly a Git repository URL and tag). See the CocoaPods specification docs for more info.

CocoaPods source_files
[CocoaPods]
spec.source_files = 'Classes/**/*.{h,m,swift}', 'More_Classes/**/*.{h,m,swift}'
File patterns:
* - Matches any file.
** - Matches directories recursively.
? - Matches any one character.
[set] - Matches any one character in set.
{p,q} - Matches either literal p or literal q.
\ - Escapes the next meta-character.

Related

How to get filepaths that match a glob without having them on the filesystem

I have a list of filepaths relative to a root directory, and am trying to determine which would be matched by a glob pattern. I'm trying to get the same results that I would get if all the files were on my filesystem and I ran Dir.glob(<my_glob_pattern>) from the root diectory.
If this is the list of filepaths:
foo/index.md
foo/bar/index.md
foo/bar/baz/index.md
foo/bar/baz/qux/index.md
and this is the glob pattern:
foo/bar/*.md
If the files existed on my filesystem, Dir.glob('foo/bar/*.md') would return only foo/bar/index.md.
The glob docs mention fnmatch, and I tried using it but found that the pattern foo/bar/*.md was matching .md files in any number of nested subdirectories, similar to what Dir.glob('foo/bar/**/*.md') would, not just the direct children of the foo/bar directory:
my_glob = 'foo/bar/*.md'
filepaths = [
'foo/index.md',
'foo/bar/index.md',
'foo/bar/baz/index.md',
'foo/bar/baz/qux/index.md',
]
# Using the provided filepaths
filepaths_that_match_pattern = filepaths.select{|path| File.fnmatch?(my_glob, path)}.sort
# If the filepaths actually existed on my filesystem
filepaths_found_by_glob = Dir.glob(my_glob).sort
raise Exception.new("They don't match!") unless filepaths_that_match_pattern == filepaths_found_by_glob
I [incorrectly] expected the above code to work, but filepaths_found_by_glob only contains the direct children, while filepaths_that_match_pattern contains all the nested children too.
How can I get the same results as Dir.glob without having the file paths on my filesystem?
You can use the flag File::FNM_PATHNAME while calling File.fnmatch function. So your function call would look like this - File.fnmatch(pattern, path, File::FNM_PATHNAME)
You can see examples related to its usage here: https://apidock.com/ruby/File/fnmatch/class
Don't use File.fnmatch, instead use Pathname.fnmatch:
require 'pathname'
PATTERN = 'foo/bar/*.md'
%w[
foo/index.md
foo/bar/index.md
foo/bar/baz/index.md
foo/bar/baz/qux/index.md
].each do |p|
puts 'path: %-24s %s' % [
p,
Pathname.new(p).fnmatch(PATTERN) ? 'matches' : 'does not match'
]
end
# >> path: foo/index.md does not match
# >> path: foo/bar/index.md matches
# >> path: foo/bar/baz/index.md matches
# >> path: foo/bar/baz/qux/index.md matches
File assumes the existence of files or paths on the drive whereas Pathname:
Pathname represents the name of a file or directory on the filesystem, but not the file itself.
Also, regarding using Dir.glob: Be careful using it. It immediately attempts to find every file or path on the drive that matches and returns the hits. On a big or slow drive, or with a pattern that isn't written well, such as when debugging or testing, your code can be tied up for a long time or make Ruby or the machine Ruby's running on go to a crawl, and it only gets worse if you're checking a shared or remote drive. As an example of what can happen, try the following at your command-line, but be prepared to hit Cntrl+C to regain control:
ls /**/*
Instead, I recommend using the Find class in the Standard Library as it will iterate over the matches. See that documentation for examples.

Why are Ruby's file related types string-based (stringly typed)?

e.g. Dir.entries returns an array of strings vs an array containing File or Dir instances.
Most methods on Dir and File types. The instances are aneamic in comparison.
There is no Dir#folders or Dir#files - instead I explicitly
loop over Dir.entries
build the path (File.expand_path) for
each item
check File.directory?
Simple use-cases like get all .svg files in this directory seem to require a number of hoops/loops/checks. Am I using Ruby wrong or does this facet of Ruby seem very un-ruby-ish?
Depending on your needs, File or Dir might do just fine.
When you need to chain commands and (rightfully) think it feels un-ruby-ish to only use class methods with string parameters, you can use Pathname. It is a standard library.
Examples
Dirs and Files
require 'pathname'
my_folder = Pathname.new('./')
dirs, files = my_folder.children.partition(&:directory?)
# dirs is now an Array of Pathnames pointing to subdirectories of my_folder
# files is now an Array of Pathnames pointing to files inside my_folder
All .svg files
If for some reason there might be folders with .svg extension, you can just filter the pathnames returned by Pathname.glob :
svg_files = Pathname.glob("folder/", "*.svg").select(&:file?)
If you want a specific syntax :
class Pathname
def files
children.select(&:file?)
end
end
aDir = Pathname.new('folder/')
p aDir.files.find_all{ |f| f.extname == '.svg' }
Iterating the Directory tree
Pathname#find will help.
Until you open the file it is just a path (string).
To open all .svg files
svgs = Dir.glob(File.join('/path/to/dir', '*.svg'))
On windows case doesn't matter in file paths, but in all unixoid systems (Linux, MacOS...) file.svg is different from file.SVG
To get all .svg files and.SVG files you need File::FNM_CASEFOLD flag.
If you want to get .svg files recursively, you need **/*.svg
svgs = Dir.glob('/path/to/dir/**/*.svg', File::FNM_CASEFOLD)
If you expect directories ending in.svg then filter them out
svgs.reject! { |path| File.directory?(path) }

Copy folder and its content in ruby

My project structure looks like this:
Project_root
|__Templates
| |__Report_Template
|
|__Product
|__product.rb
What code should I write in product.rb in order to copy Report_Template folder and its content into Product folder?
I tried to use FileUtils.cp_r, but then I will have to give full path of source folder and if in a future I move Project_root, there will be issues.
As Kenney says, you can get the path from which the program started, in __dir__. Here I use Pathname class for easier path manipulation, but it is entirely optional (you can use File#join etc. just as well):
require 'pathname'
templates_pathname = Pathname.new(__dir__) + "../Templates/Report_Template"
# optional:
templates_path = templates_pathname.realpath.to_s
Pathname#realpath will give you the absolute path, if you need it; but FileUtils#cp_r will happily accept a Pathname (i.e. templates_pathname above), and won't mind it's not absolute.

Implement .gitignore behavior in a shell script?

I'm writing a shell script that syncs files and I want to give users the ability to exclude certain files from syncing by creating a .syncignore file similar to Git's .gitignore file. According to the gitignore documentation, and my own experiments, these exclusion rules are more complicated than a simple glob match. Some examples:
If you have foo in your .gitignore file, it will exclude foo appearing anywhere in the path (e.g. ./foo, ./bar/foo, and ./bar/foo/baz would be excluded) but not partial matches of foo (e.g. ./foobar, ./bar/foobar/baz would NOT be excluded).
If you include a slash, then the rule is applied relative to the current directory. For example, if you have /foo in your .gitignore file, it will exclude ./foo but not ./bar/foo.
You can include wildcards. For example, foo* will exclude ./foo, ./foobar, and ./bar/foobar/baz.
Is there any easy way to replicate the exclusion rules for .gitignore in a shell script on OS X?
Use rsync to synchronize the files. Use its existing include/exclude pattern support. Put the rules in .rsync-filter and pass the -F flag to make it read the patterns from that file.
rsync man page
Just use git. Make sure you have git 2.3.0 or later on both sides, and use push-to-deploy.

Buildr - exclude directory from resources

In Buildr you can exclude all files in a directory by doing the following:
resources.exclude 'scratch/*'
Is it possible to exclude the directory as well? The Buildr documentation mentions:
The filter always excludes the CVS and .svn directories, and all files
ending with .bak or ~, so no need to worry about these.
My company uses Dimensions as its source control, it creates a .metadata folder in every directory much like subversion does with the .svn folder.
These exclusions are actually inherited from Rake (rake/file_list.rb)
module Rake
...
class FileList
...
DEFAULT_IGNORE_PATTERNS = [
/(^|[\/\\])CVS([\/\\]|$)/,
/(^|[\/\\])\.svn([\/\\]|$)/,
/\.bak$/,
/~$/
]
...
end
end
so it's possible to monkey-patch the defaults, if that's what you want.
Alternatively, you can also add exclusions directly on a FileList by passing a block and calling the exclude method,
pkg_files = FileList.new('lib/**/*') do |fl|
fl.exclude(/\bCVS\b/)
end
Since Buildr filters (http://buildr.apache.org/rdoc/classes/Buildr/Filter.html) expose their underlying FileList, you can simply do:
resources.sources do |fl|
fl.exclude(/\.metadata/)
end

Resources