Ruby中Marshal::load方法的proc参数作用及使用示例咨询
proc Argument in Marshal::load Great question! It’s totally relatable that the official Ruby docs only give a brief description of this parameter without real-world examples. Let’s break down how this proc works and walk through practical use cases.
First, a quick recap of the official docs excerpt you shared:
load( source [, proc] ) → obj
将source中的序列化数据转换为Ruby对象(可能包含关联的从属对象)并返回结果。source可以是IO实例或响应to_str方法的对象。如果指定了proc参数,每个对象在反序列化过程中都会被传递给该proc。
In plain terms: the proc acts as a callback that runs for every single object (including nested child objects) as it’s deserialized from the source. You can use this to log, modify, validate, or transform objects during the load process.
Example 1: Logging Deserialized Objects
This is a simple use case to track exactly what’s being loaded, which can be helpful for debugging:
# First, serialize some nested data serialized_data = Marshal.dump([{username: "jane_doe", posts: 15}, "welcome message", 2024]) # Create a proc to log each object's type and content logging_proc = Proc.new do |obj| puts "[Deserialized] Type: #{obj.class} | Value: #{obj.inspect}" end # Load the data with the logging proc result = Marshal.load(serialized_data, logging_proc)
When you run this, you’ll see output for every object in the nested structure:
[Deserialized] Type: Array | Value: [{:username=>"jane_doe", :posts=>15}, "welcome message", 2024] [Deserialized] Type: Hash | Value: {:username=>"jane_doe", :posts=>15} [Deserialized] Type: String | Value: "jane_doe" [Deserialized] Type: Integer | Value: 15 [Deserialized] Type: String | Value: "welcome message" [Deserialized] Type: Integer | Value: 2024
Example 2: Modifying Objects During Deserialization
You can use the proc to transform objects as they’re loaded—like updating old data formats or adding metadata:
# Serialize a list of product names serialized_products = Marshal.dump(["Laptop", "Phone", ["Headphones", "Charger"]]) # A proc to add a timestamp suffix to all strings modify_proc = Proc.new do |obj| obj << " (loaded at #{Time.now.strftime("%H:%M")})" if obj.is_a?(String) end # Load and modify the data updated_products = Marshal.load(serialized_products, modify_proc) puts updated_products.inspect
The output will show every string (including nested ones) modified:
["Laptop (loaded at 14:30)", "Phone (loaded at 14:30)", ["Headphones (loaded at 14:30)", "Charger (loaded at 14:30)"]]
Example 3: Validating Objects for Security/Integrity
If you’re loading serialized data from a semi-trusted source, you can use the proc to validate objects before they’re fully returned:
class Order attr_accessor :id, :total def initialize(id, total) @id = id @total = total end end # Serialize an order with an invalid negative total serialized_order = Marshal.dump(Order.new(123, -50)) # A proc to validate order totals validation_proc = Proc.new do |obj| if obj.is_a?(Order) && obj.total < 0 raise ArgumentError, "Invalid order ##{obj.id}: Total cannot be negative!" end end # Attempt to load the invalid order begin Marshal.load(serialized_order, validation_proc) rescue ArgumentError => e puts e.message # Output: Invalid order #123: Total cannot be negative! end
Key Notes
- The proc runs for every object in the deserialization tree, including nested arrays, hashes, and custom class instances.
- This is especially useful for data migration (updating old object structures to new ones) or adding extra safety checks (though remember:
Marshalis not designed for untrusted data—this is just an extra layer).
内容的提问来源于stack exchange,提问作者noname

