I need to store some simple properties in a file and access them from Ruby.
I absolutely love the .properties file format that is the standard for such things in Java (using the java.util.Properties class)... it is simple, easy to use and easy to read.
So, is there a Ruby class somewhere that will let me load up some key value pairs from a file like that without a lot of effort?
I don't want to use XML, so please don't suggest REXML (my purpose does not warrant the "angle bracket tax").
I have considered rolling my own solution... it would probably be about 5-10 lines of code tops, but I would still rather use an existing library (if it is essentially a hash built from a file)... as that would bring it down to 1 line....
UPDATE: It's actually a straight Ruby app, not rails, but I think YAML will do nicely (it was in the back of my mind, but I had forgotten about it... have seen but never used as of yet), thanks everyone!
Is this for a Rails application or a Ruby one?
Really with either you may be able to stick your properties in a yaml file and then YAML::Load(File.open("file")) it.
NOTE from Mike Stone: It would actually be better to do:
File.open("file") { |yf| YAML::load(yf) }
or
YAML.load_file("file")
as the ruby docs suggest, otherwise the file won't be closed till garbage collection, but good suggestion regardless :-)
Another option is to simply use another Ruby file as your configuration file.
Example, create a file called 'options'
{
:blah => 'blee',
:foo => 'bar',
:items => ['item1', 'item2'],
:stuff => true
}
And then in your Ruby code do something like:
ops = eval(File.open('options') {|f| f.read })
puts ops[:foo]
YAML will do it perfectly as described above. For an example, in one of my Ruby scripts I have a YAML file like:
migration:
customer: Example Customer
test: false
sources:
- name: Use the Source
engine: Foo
- name: Sourcey
engine: Bar
which I then use within Ruby as:
config = YAML.load_file(File.join(File.dirname(__FILE__), ARGV[0]))
puts config['migration']['customer']
config['sources'].each do |source|
puts source['name']
end
inifile - http://rubydoc.info/gems/inifile/2.0.2/frames will support basic .properties files and also .ini files with [SECTIONS] eg.
[SECTION]
key=value
YAML is good when your data has complex structure but can be fiddly with spaces, tabs, end of lines etc - which might cause problems if the files are not maintained by programmers. By contrast .properties and .ini files are more forgiving and may be suitable if you don't need the deep structure available through YAML.
Devender Gollapally wrote a class to do precisely that:
...though i'd recommend better to use a YAML file.
Instead of the .properties style of config file, you might consider using YAML. YAML used in Ruby on Rails for database configuration, and has gained in popularity in other languages (Python, Java, Perl, and others).
An overview of the Ruby YAML module is here: http://www.ruby-doc.org/core/classes/YAML.html
And the home page of YAML is here: http://yaml.org
Related
I need to be able to make a Ruby application (no Rails, if possible) that opens an external YAML file that has over 104K lines of code in it, reads from it and filters out the following three things:
!ruby/object:EvtEvent
!ruby/object:NwsPost
!ruby/object:Asset
and then outputs these things to an XML file that would have to be built by the Ruby program.
I am unclear how to start with setting this up, as I am only a junior-level developer with one year's experience.
Although I found something on Stack Overflow that shows this snippet of a code example on using Nokogiri, I don't know exactly where to put this code which I would have to modify for my situation:
require 'yaml'
require 'nokogiri'
yaml = "getOrderDetails:
Id: '114'
Name: 'XYZ'"
doc = YAML.load yaml
output = Nokogiri::XML::Builder.new do |xml|
xml.product{
xml.id doc["getOrderDetails"]["Id"]
xml.name doc["getOrderDetails"]["Name"]
}
end
puts output.to_xml
#=> <?xml version="1.0"?>
#=> <product>
#=> <id>114</id>
#=> <name>XYZ</name>
#=> </product>
How would I code the init.rb file to launch a Ruby program that would open the YAML file in question, read from it, and then output it to XML?
What other Ruby files would I need to put in my lib folder for such a Ruby program to handle this task?
The code can go wherever it's convenient. Ruby has no real expectation of file locations; You just run them. Your development team probably has guidelines, so you need to talk to them.
"init.rb" is a non-descriptive name for a file. Try to use something more indicative of the purpose of the script.
Reading a remove file for this purpose is easy with OpenURI:
foo = open('http://domain.com/path/to/file.yaml').read
will return the contents of the file and store them in the variable foo.
The contents of the YAML can be parsed easily using:
yaml = YAML.load(foo)
At that point haml will contain an array or a hash, which can then be accessed as normal.
What's more interesting is that, once OpenURI is loaded, it will patch the open method, which should make it possible to do something like:
require 'open-uri'
yaml = YAML.load_file('http://domain.com/path/to/file.yaml')
YAML has to open a file to load from the disk, which is what load_file normally does, and after OpenURI does its magic the YAML class should have inherited that magic. I haven't tested that but it should work.
Nokogiri's Builder interface is probably a good way to go.
I need to parse a large (4gb) xml file in ruby, preferably with nokogiri. I've seen a lot of code exampled using
File.open(path)
but this takes too much time in my case. Is there an option to read the xml node by node in order to prevent loading the file at ones. Or what would be the fastest way to parse such a large file.
Best,
Phil
You can try using Nokogiri::XML::SAX
The basic way a SAX style parser works is by creating a parser,
telling the parser about the events we’re interested in, then giving
the parser some XML to process. The parser will notify you when it
encounters events your said you would like to know about.
I do this kind of work with LibXML http://xml4r.github.io/libxml-ruby/ (require 'xml') and its LibXML::XML::Reader API. It's simpler than SAX and allows you to make almost everything. REXML includes a similar API also, but it's quite buggy. Stream APIs like the one I mention or SAX shouldn't have any problem with huge files. I have not tested Nokogiri.
you may like to try this out - https://github.com/amolpujari/reading-huge-xml
HugeXML.read xml, elements_lookup do |element|
# => element{ :name, :value, :attributes}
end
I also tried using ox
I am currently writing a Ruby script to manage my dotfiles. I want to keep a list of the tracked dotfiles, and am not quite sure how to go about this.
The thing is that the list would be so simple, e.g
tmux.conf
zshrc
vimrc
so I feel using yml, xml or various other formats would be overkill. I do not need to store indexes, paths, order or anything of the sort. However, storing the filesnames in a file separated by newlines or commas still feel kind of "dumb". How should I go about this?
UPDATE
It seems like my question wasn't clear enough. I know how to write to and read from files and DB using Ruby. My question was meant to be something like What is the best practice for storing single-values in a file?
Should I use a known file format like YAML or XML, or what would you choose?
through this you can get all file name in an array now you can write them to file
file_names = Dir.entries(".").select {|f| !File.directory? f}
file = File.open(local_filename, 'w')
file_names.each do |name|
file.write(name + "\n")
end
I'd simply go with new-line separated values or storing it inside the script. It's definitely not dumb, it's just the way you do things like that.
We have one Sinatra app and one Backbone app.
I saw Sharing the same codebase across multiple apps but didn't understand it or how I could implement it.
This question is not really specific to Sinatra or Backbone; it could be pretty much any apps. Using Heroku and Git
One idea is to put the HTML on S3, but we aren't using S3 to store HTML. And how would you get it from Git onto S3? It seems very convoluted.
So, is there a good way of sharing HTML templates between the apps?
We do it by having a containing parent directory, and well-defined paths to the common files, and by having a common YAML file used to tell different apps where to look.
Create a common YAML file that contains a Hash, with the keys being a common-name for a particular resource or path to resources, and the value being the absolute path to that on the disk.
For instance:
---
html: /absolute/path/to/shared/html
images: /absolute/path/to/shared/images
main_css: /absolute/path/to/shared/styles.css
Load that using Ruby with:
require 'yaml'
SHARED_RESOURCES = YAML.load_file('/absolute/path/to/shared_resources.yaml')
# => {"html"=>"/absolute/path/to/shared/html", "images"=>"/absolute/path/to/shared/images", "main_css"=>"/absolute/path/to/shared/styles.css"}
Use the resulting SHARED_RESOURCES hash to retrieve the information you need:
main_css = SHARED_RESOURCES['main_css']
# => "/absolute/path/to/shared/styles.css"
You can use that same YAML file from ANY language that can read YAML, or where you can open that file and parse its contents. At that point, all your code-bases can play from the same sheet of music, and will know how to access the common files when necessary.
For instance, from Perl:
use YAML;
$SHARED_RESOURCES = Load('
---
html: /absolute/path/to/shared/html
images: /absolute/path/to/shared/images
main_css: /absolute/path/to/shared/styles.css
');
print $SHARED_RESOURCES->{'main_css'}, "\n";
>> /absolute/path/to/shared/styles.css
If you want to get fancier, use a database to hold those shared resources. Either way, the idea is there's just one place for the code to look for a particular resource/file.
Using Mechanize with Ruby I get a certain file using agent.get('http://example.com/foo.torrent'), with FileUtils or otherwise, how do I save this file to my hard drive (for instance, in a directory wherefrom the script is running)?
P.S. class => WWW::Mechanize::File
Well, WWW::Mechanize::File has a save_as instance method, so I suppose something like this might work:
agent.get('http://example.com/foo.torrent').save_as 'a_file_name'
Please note that the Mechanize::File class is not the most appropriate for large files. In those cases, one should use the Mechanize::Download class instead, as it downloads the content in small chunks to disk. The file will be downloaded to where the script is running (although you can specify a different path as well). You need to set the default parser first, create a new one or modify an existing parser. Then, save it to the desired path:
agent.pluggable_parser.default = Mechanize::Download
agent.get( "http://example.com/foo.torrent}").save("path/to/a_file_name")
Check here and here for more details. Also, there's a similar question here in Stackoverflow.