Where is the Ruby YAML.load_file(“some_file.yml”) equivalent?
When parse a YAML file use YAML.parse(File.read("some_file.yml"), sometimes, need a object to present a empty YAML::Any document if the yaml document not exists instead of Nil, in Ruby, it is simple, just a empty hash {} is enough, how to present it in Crystal? what i means is, somethings like YAML::Any.new, but this not work.
EDIT: I know the answer, YAML.parse("{}"), there may also be better answers.
Why Hash not #sort_by?
e.g. we want output sorted hash by it keys.
in Ruby, hash.sort_by {|k, v| k.to_s }, it not work in Crystal, we have to do: hash.to_a.sort_by {|x| x[0]}.to_h
What is the different for following chop and strip usage?
#lchop(prefix : Char | String) : String
Returns a new String with prefix removed from the beginning of the string.
#lstrip(char : Char) : String
Returns a new string with leading occurrences of char removed.
#lstrip(chars : String) : String
Returns a new string where leading occurrences of any char in chars are removed.
Given a YAML::Any, how to convert it into a Hash(String, String)?
require "yaml"
x = {"test1" => "sleep 100", "test2" => "sleep 150"}.to_yaml
# Given yaml_any object.
yaml_any = YAML.parse(x)
# How to convert it into a Hash(String, String)?
z = yaml_any.as_h(String, String) # this not work
Honestly, when it comes to dealing with YAML or JSON, using Type.from_yaml rather than YAML.parse is better nearly every time. Working with a YAML::Any is okay when you’re testing an idea, but it’s painful to work with for anything nontrivial. For example, if you’re doing it for config:
require “yaml”
struct Config
include YAML::Serializable
getter database_url : URI
getter admin_email : String
# This is also a good way to get that hash typecast, btw
getter env : Hash(String, String)
end
Speaking of converting YAML::Any to Hash(String, String), if the file only contains string-to-string mappings, you can use Hash(String, String).from_yaml as a direct replacement of YAML.parse.
You still need to do the type conversions, for the most part, even with YAML::Any using .as_s. Using YAML::Any spreads those type conversions out instead of keeping them together.
I was talking about using it in place of YAML.parse, so this would be further up the stack, not passing the YAML::Any to from_yaml.
Yeah, I suppose it might be a useful shortcut. And it could also easily enhance error messages with the name of the file being loaded.
This would apply to all parsers which parse data that is regular loaded from files (JSON, INI, CSV).
Hi, I don’t know if I do something wrong, maybe for current special case, i need convert a YAML::Any object to a Hash frequently, same discussed in above question #5.
Following is example:
require "yaml"
x = {"a" => 100, "b" => 200}.to_yaml
y = YAML.parse(x)
h = y.as_h
p! y # => {"a" => 100, "b" => 200}
p! typeof(y) # => YAML::Any
p! h # => {"a" => 100, "b" => 200}
p! typeof(h) # => Hash(YAML::Any, YAML::Any)
The issue is:
I expect to get a hash of String => Int32 back from the YAML::Any object, instead of {} of YAML::Any => YAML::Any.
The really use case is, above YAML::Any object is only one part of a big YAML document which parsed use YAML.parse, I an ensure
this object is a Hash(String, Int32) compatible object, i need to convert to hash to use some Hash methods, how can i do that?
Is there a way to convert YAML::Any back to YAML document? Or, give the underneath original document?
e.g.
y = YAML.parse(x)
Hash(String, Int32).from_yml(y.to_yaml_document)
# Or, Can we support pass Type into as_h?
y.as_h(String,Int32)
Is the structure of the YAML you need to parse known ahead of time? If so, then IMO the better way to do it would be to define some types to represent it using YAML::Serializable - Crystal 1.7.0-dev. Then can just do MyType.from_yaml x. Then you do not have to deal with YAML::Any at all, and have more flexibility as you can add additional methods etc.
Alternatively, the data is fairly simple, you could also do Hash(String, Int23).from_yaml x. But this could get messy if its more than a simple hash. Otherwise yes, I’m pretty sure you can just do y.to_yaml.
Yes, i am trying to change to this, although, I was planing going to do this later.
When use #from_yaml(yaml_file), if yaml_file not exists, get error message like this:
Expected mapping, not YAML::Nodes::Scalar at line 1, column 1 (YAML::ParseException
from /home/zw963/Crystal/share/crystal/src/yaml/nodes/nodes.cr:30:9 in 'raise'
from /home/zw963/Crystal/share/crystal/src/yaml/serialization.cr:187:7 in 'initialize:__context_for_yaml_serializable:__node_for_yaml_serializable'
This is really confusing, i thought we need create a issue to discuss how to fix this, @Blacksmoke16 what do you think?
@zw963 You would just need to implement that yourself. E.g. something like:
struct ProcessOption
def merge(other : self)
# Determine if you should use @quantity or other.quantity
end
end
This would ofc be easier with a class as you could just mutate self while in the struct case, would prob have to return a new instance with the merged values.
EDIT: Or option 2 would be merge the YAML before deserializing it somehow.