【完全ガイド】RubyでJSONをパースする7つの実践的なテクニック

Ruby の JSON 解析の基礎知識

JSON とは:Web アプリケーションの重要性

JSONは「JavaScript Object Notation」の略で、データ交換フォーマットとして現代のWeb開発では不可欠な存在となっています。以下の特徴から、多くの開発者に選ばれています:

  • 人間にとって読み書きしやすい
  • プログラムでの処理が容易
  • 言語に依存しない
  • データ構造を直感的に表現できる

例えば、ユーザー情報を表すJSONは以下のような形式になります:

{
  "id": 1,
  "name": "山田太郎",
  "email": "yamada@example.com",
  "interests": ["Ruby", "Web開発", "API設計"],
  "address": {
    "city": "東京",
    "prefecture": "東京都"
  }
}

Ruby 関連の JSON ライブラリの概要

Rubyでは、JSONを扱うための主要なライブラリが用意されています:

  1. 標準ライブラリ json
  • Ruby 1.9以降に標準搭載
  • 基本的なJSON処理に必要な機能を提供
  • 最も一般的に使用されるライブラリ
require 'json'  # 標準ライブラリの読み込み
  1. oj (Optimized JSON)
  • C言語で実装された高速なJSONパーサー
  • 標準ライブラリより高速な処理が可能
  • より多くの機能とオプションを提供
gem 'oj'  # Gemfileに追加
require 'oj'  # ライブラリの読み込み
  1. multi_json
  • 複数のJSONライブラリを抽象化
  • 最適なJSONパーサーを自動選択
  • フレームワークやライブラリでよく使用
gem 'multi_json'  # Gemfileに追加
require 'multi_json'  # ライブラリの読み込み

各ライブラリの特徴比較:

ライブラリ速度メモリ使用量機能の豊富さ導入の容易さ
json(標準)普通基本的最も簡単
oj高速豊富要インストール
multi_json可変豊富要インストール

JSONの基本的なデータ型とRubyのオブジェクトの対応:

  1. 数値型
  • JSON: 整数値、浮動小数点数
  • Ruby: Integer, Float
  1. 文字列型
  • JSON: “文字列”
  • Ruby: String
  1. 真偽値
  • JSON: true, false
  • Ruby: TrueClass, FalseClass
  1. 配列
  • JSON: [値1, 値2, …]
  • Ruby: Array
  1. オブジェクト
  • JSON: {“キー”: 値, …}
  • Ruby: Hash

この基礎知識を踏まえることで、以降の章でより実践的なJSONパース処理の実装方法を理解しやすくなります。

基本的なJSONパース処理の実装方法

require ‘json’の使い方と基本構文

RubyでのJSON処理は、標準ライブラリ「json」を使用することから始まります。以下に基本的な使い方を示します:

# JSONライブラリの読み込み
require 'json'

# 基本的な使い方の例
json_string = '{"name": "佐藤花子", "age": 25}'
parsed_data = JSON.parse(json_string)
puts parsed_data["name"]  # => 佐藤花子
puts parsed_data["age"]   # => 25

requireを使用する際の重要なポイント:

  1. ライブラリの読み込み確認
# 既に読み込まれているか確認
if defined?(JSON)
  puts "JSONライブラリは既に読み込まれています"
else
  require 'json'
  puts "JSONライブラリを読み込みました"
end
  1. バージョン確認
# JSONライブラリのバージョン確認
puts JSON::VERSION  # 現在使用しているバージョンを表示

JSON.parseメソッドの詳細な使用方法

JSON.parseメソッドには、様々なオプションと使用方法があります:

  1. 基本的なパース処理
# 単純な文字列からのパース
json_string = '{"id": 1, "status": "active"}'
data = JSON.parse(json_string)
puts data["id"]      # => 1
puts data["status"]  # => active
  1. シンボルキーでのパース
# キーをシンボルとして取得
data = JSON.parse(json_string, symbolize_names: true)
puts data[:id]      # => 1
puts data[:status]  # => active
  1. 配列を含むJSONのパース
# 配列を含むJSONデータ
array_json = '[
  {"id": 1, "name": "田中"},
  {"id": 2, "name": "鈴木"}
]'

users = JSON.parse(array_json)
users.each do |user|
  puts "ID: #{user['id']}, Name: #{user['name']}"
end
  1. ネストされたデータのパース
# ネストされたJSONデータ
nested_json = '{
  "user": {
    "profile": {
      "name": "山本",
      "age": 30,
      "hobbies": ["読書", "旅行"]
    }
  }
}'

data = JSON.parse(nested_json)
puts data["user"]["profile"]["name"]     # => 山本
puts data["user"]["profile"]["hobbies"]  # => ["読書", "旅行"]

JSON.parseのオプション一覧:

オプション説明使用例
symbolize_names: trueキーをシンボルとして扱うJSON.parse(json, symbolize_names: true)
max_nesting: 100ネストの最大深度を指定JSON.parse(json, max_nesting: 50)
allow_nan: trueNaN, Infinity, -Infinityを許可JSON.parse(json, allow_nan: true)
create_additions: falseJSON拡張を無効化JSON.parse(json, create_additions: false)

実装時の重要なポイント:

  1. 文字エンコーディングの考慮
# UTF-8でエンコードされていることを確認
json_string.force_encoding('UTF-8')
data = JSON.parse(json_string)
  1. メソッドチェーンの活用
# パースと同時にデータ取得
user_name = JSON.parse(json_string)["user"]["name"]

このような基本的なパース処理の理解は、より複雑なJSONデータを扱う際の基礎となります。次章では、より実践的なパーステクニックについて説明します。

実践的な JSON パーステクニック集

大規模な JSON ファイルの効率的な処理方法

大規模なJSONファイルを処理する際は、メモリ使用量と処理速度を考慮する必要があります。以下に効率的な処理方法を示します:

  1. ストリーミング処理の活用
require 'json'
require 'oj'  # 大規模ファイル用に高速なOJを使用

# ストリーミング処理の実装
def process_large_json(file_path)
  File.open(file_path, 'r') do |file|
    parser = Oj.load_file(file_path, mode: :compat)
    parser.each do |record|
      # 1レコードずつ処理
      yield record if block_given?
    end
  end
end

# 使用例
process_large_json('large_data.json') do |record|
  puts record['id']
end
  1. チャンク処理による最適化
def process_in_chunks(file_path, chunk_size = 1000)
  records = []
  File.open(file_path, 'r') do |file|
    parser = Oj.load_file(file_path, mode: :compat)
    parser.each_with_index do |record, index|
      records << record
      if records.size >= chunk_size
        yield records
        records = []
      end
    end
    yield records unless records.empty?
  end
end

# チャンク処理の使用例
process_in_chunks('large_data.json') do |chunk|
  chunk.each { |record| process_record(record) }
end

ネスト化された JSON データの正しい取り扱い

複雑なネスト構造を持つJSONデータを効率的に処理する方法を紹介します:

  1. 深いネストの安全な取り扱い
# dig メソッドを使用した安全なアクセス
def safe_dig(hash, *keys)
  begin
    keys.reduce(hash) { |h, key| h && h[key] }
  rescue StandardError
    nil
  end
end

# 使用例
complex_data = JSON.parse(complex_json)
value = safe_dig(complex_data, 'user', 'settings', 'preferences', 'theme')
puts value || 'デフォルト値'
  1. 再帰的な処理の実装
def process_nested_json(data)
  case data
  when Hash
    data.transform_values { |v| process_nested_json(v) }
  when Array
    data.map { |item| process_nested_json(item) }
  else
    data
  end
end

# 特定のキーを持つ要素を全て抽出する例
def find_all_by_key(data, target_key, results = [])
  case data
  when Hash
    data.each do |key, value|
      results << value if key == target_key
      find_all_by_key(value, target_key, results)
    end
  when Array
    data.each { |item| find_all_by_key(item, target_key, results) }
  end
  results
end

日本語を含むJSONデータのエンコーディング対応

日本語データを正しく処理するためのテクニックを紹介します:

  1. エンコーディング指定によるパース
# 日本語を含むJSONの読み込みと書き込み
def process_japanese_json(input_file, output_file)
  # 読み込み時のエンコーディング指定
  json_str = File.read(input_file, encoding: 'UTF-8')
  data = JSON.parse(json_str)

  # 書き込み時のエンコーディング指定
  File.open(output_file, 'w:UTF-8') do |f|
    f.puts JSON.generate(data, {
      ascii_only: false,  # 日本語をエスケープしない
      pretty_generate: true  # 整形して出力
    })
  end
end
  1. 文字化け対策
def sanitize_encoding(text)
  text.encode('UTF-8', invalid: :replace, undef: :replace, replace: '?')
end

def process_with_encoding(json_str)
  # 文字化け対策を施した処理
  sanitized_json = sanitize_encoding(json_str)
  begin
    data = JSON.parse(sanitized_json)
    # 日本語を含むデータの処理
    data.transform_values do |value|
      value.is_a?(String) ? sanitize_encoding(value) : value
    end
  rescue JSON::ParserError => e
    puts "JSONのパースに失敗しました: #{e.message}"
    nil
  end
end

実践的なテクニックをまとめた早見表:

状況推奨テクニック注意点
大規模データストリーミング処理メモリ使用量に注意
深いネストdigメソッド活用nil対策を忘れずに
日本語データUTF-8指定文字化け確認
複雑な変換再帰処理スタックオーバーフロー注意

これらのテクニックを状況に応じて適切に組み合わせることで、より効率的なJSONデータの処理が可能になります。

エラーハンドリングのベストプラクティス

よくあるJSONパースエラーとその解決方法

JSONパース処理で発生する主なエラーとその対処法を解説します:

  1. JSON::ParserError の処理
def safe_parse(json_string)
  begin
    JSON.parse(json_string)
  rescue JSON::ParserError => e
    # エラーログの記録
    logger.error "JSONパースエラー: #{e.message}"
    # エラーの詳細を含むハッシュを返す
    {
      error: true,
      message: "Invalid JSON format",
      details: e.message
    }
  end
end

# 使用例
result = safe_parse('{"invalid": "json"')
puts result[:error] ? "エラー: #{result[:message]}" : "成功"

よくあるエラーとその原因:

エラー種類主な原因解決方法
構文エラー括弧の不一致、カンマの位置不正JSONの整形・バリデーション
エンコーディングエラー不正な文字コード適切なエンコーディング指定
メモリ不足大きすぎるJSONデータストリーミング処理の採用
キー重複同じキーが複数存在データのクリーニング

例外処理を使った安定なコードの書き方

  1. 階層的な例外処理
def process_json_with_validation(json_string)
  begin
    # パース処理
    data = JSON.parse(json_string)

    # バリデーション
    validate_json_structure(data)

    # データ処理
    process_data(data)

  rescue JSON::ParserError => e
    handle_parser_error(e)
  rescue ValidationError => e
    handle_validation_error(e)
  rescue StandardError => e
    handle_general_error(e)
  ensure
    # クリーンアップ処理
    cleanup_resources
  end
end

# 各エラーハンドリング関数
def handle_parser_error(error)
  {
    status: :error,
    type: :parser_error,
    message: error.message,
    timestamp: Time.now
  }
end

def handle_validation_error(error)
  {
    status: :error,
    type: :validation_error,
    message: error.message,
    timestamp: Time.now
  }
end
  1. カスタム例外クラスの定義
module JSONProcessor
  class ValidationError < StandardError; end
  class DataTypeError < StandardError; end

  def self.validate_json_structure(data)
    raise ValidationError, "データが空です" if data.nil?
    raise DataTypeError, "配列データが必要です" unless data.is_a?(Array)
    # その他のバリデーション
  end
end

# 使用例
begin
  JSONProcessor.validate_json_structure(data)
rescue JSONProcessor::ValidationError => e
  puts "バリデーションエラー: #{e.message}"
rescue JSONProcessor::DataTypeError => e
  puts "データ型エラー: #{e.message}"
end

エラーハンドリングのベストプラクティス:

  1. 段階的なエラーチェック
def process_with_validation(json_string)
  # 1. 基本的なJSONフォーマットチェック
  return { error: "入力が空です" } if json_string.nil? || json_string.empty?

  # 2. パース処理
  begin
    data = JSON.parse(json_string)
  rescue JSON::ParserError => e
    return { error: "JSONパースエラー: #{e.message}" }
  end

  # 3. データ構造の検証
  unless valid_structure?(data)
    return { error: "不正なデータ構造です" }
  end

  # 4. ビジネスロジックの実行
  process_business_logic(data)
end

# 構造チェックのヘルパーメソッド
def valid_structure?(data)
  data.is_a?(Hash) &&
    data.key?("required_field1") &&
    data.key?("required_field2")
end
  1. ロギングと監視
def parse_with_logging(json_string)
  begin
    start_time = Time.now
    result = JSON.parse(json_string)
    log_success(start_time)
    result
  rescue => e
    log_error(e, start_time)
    raise
  end
end

def log_success(start_time)
  duration = Time.now - start_time
  logger.info "JSONパース成功 (所要時間: #{duration}秒)"
end

def log_error(error, start_time)
  duration = Time.now - start_time
  logger.error "JSONパースエラー: #{error.message} (所要時間: #{duration}秒)"
  notify_monitoring_service(error) if critical_error?(error)
end

これらの実装例とベストプラクティスを適切に組み合わせることで、より安定したJSONパース処理を実現できます。

パフォーマンス最適化のポイント

JSONパース処理の速度を向上させるテクニック

パフォーマンスを最大限に引き出すための実装テクニックを紹介します:

  1. 高速なJSONパーサーの活用
# Ojライブラリの使用例
require 'oj'

def fast_parse(json_string)
  # モードの指定でさらなる最適化
  Oj.load(json_string, mode: :compat)
end

# ベンチマーク比較
require 'benchmark'

json_string = File.read('large_file.json')
Benchmark.bm do |x|
  x.report('標準JSON:') { JSON.parse(json_string) }
  x.report('Oj:') { Oj.load(json_string) }
end
  1. パース結果のキャッシュ活用
require 'redis'

class JSONCache
  def initialize
    @redis = Redis.new
    @expiry = 3600 # 1時間
  end

  def parse_with_cache(json_string)
    # キャッシュキーの生成
    cache_key = "json_cache:#{Digest::MD5.hexdigest(json_string)}"

    # キャッシュの確認
    cached = @redis.get(cache_key)
    return Marshal.load(cached) if cached

    # パースして結果をキャッシュ
    result = JSON.parse(json_string)
    @redis.setex(cache_key, @expiry, Marshal.dump(result))
    result
  end
end
  1. 並列処理の活用
require 'parallel'

def parallel_json_processing(json_array)
  Parallel.map(json_array, in_threads: 4) do |json_string|
    JSON.parse(json_string)
  end
end

# 使用例
json_strings = ['{"id": 1}', '{"id": 2}', '{"id": 3}']
results = parallel_json_processing(json_strings)

メモリ使用量を重視するための実装方法

メモリ効率を考慮した実装テクニックを紹介します:

  1. ストリーミングパーサーの実装
require 'json/stream'

class StreamingJSONParser
  def parse_file(file_path)
    parser = JSON::Stream::Parser.new
    results = []

    parser.start_document { puts "パース開始" }
    parser.end_document { puts "パース完了" }

    parser.start_object do |key|
      # オブジェクト開始時の処理
    end

    parser.end_object do
      # オブジェクト終了時の処理
    end

    parser.value do |value|
      results << value if value.is_a?(Hash)
    end

    File.open(file_path, 'r') do |file|
      file.each_line do |line|
        parser << line
      end
    end

    results
  end
end
  1. メモリ使用量の監視と制御
class MemoryAwareParser
  MAX_MEMORY_MB = 512

  def parse_with_memory_control(json_string)
    current_memory = get_memory_usage

    if current_memory > MAX_MEMORY_MB
      GC.start # ガベージコレクションを強制実行
      raise MemoryError if get_memory_usage > MAX_MEMORY_MB
    end

    JSON.parse(json_string)
  end

  private

  def get_memory_usage
    `ps -o rss= -p #{Process.pid}`.to_i / 1024 # MBに変換
  end
end

パフォーマンス最適化のチェックリスト:

最適化項目実装方法効果トレードオフ
パース速度Ojの使用2-3倍の高速化依存関係の追加
メモリ使用量ストリーミング少ないメモリ実装の複雑化
並列処理Parallel利用処理時間短縮リソース消費増加
キャッシュRedis活用繰り返し処理の高速化インフラ要件増加

性能測定と監視のベストプラクティス:

class PerformanceMonitor
  def self.measure_parse_performance(json_string)
    memory_before = `ps -o rss= -p #{Process.pid}`.to_i
    time_started = Time.now

    result = JSON.parse(json_string)

    time_elapsed = Time.now - time_started
    memory_after = `ps -o rss= -p #{Process.pid}`.to_i
    memory_used = memory_after - memory_before

    {
      parse_time_ms: (time_elapsed * 1000).round(2),
      memory_used_kb: memory_used,
      data_size_bytes: json_string.bytesize
    }
  end
end

これらの最適化テクニックを適切に組み合わせることで、効率的なJSONパース処理を実現できます。

セキュリティ対策と注意点

安全なJSONパース処理のためのチェックリスト

JSONパース処理におけるセキュリティリスクと対策について解説します:

  1. 入力値の検証と制限
class SecureJSONParser
  MAX_DEPTH = 20
  MAX_SIZE = 1024 * 1024 # 1MB

  def safe_parse(json_string)
    # サイズチェック
    raise "JSONデータが大きすぎます" if json_string.bytesize > MAX_SIZE

    # 深さ制限付きでパース
    JSON.parse(json_string, max_nesting: MAX_DEPTH)
  rescue JSON::ParserError => e
    log_security_event("JSONパースエラー", e.message)
    raise "不正なJSONフォーマット"
  end

  private

  def log_security_event(type, message)
    SecurityLogger.log(
      event_type: type,
      message: message,
      timestamp: Time.now,
      source_ip: request.remote_ip
    )
  end
end
  1. シリアライズ攻撃の防止
class JSONValidator
  ALLOWED_CLASSES = [String, Integer, Float, TrueClass, FalseClass, NilClass]

  def validate_object(obj, depth = 0)
    return if depth > 10 # 最大深度の制限

    case obj
    when Hash
      obj.each do |key, value|
        validate_key(key)
        validate_object(value, depth + 1)
      end
    when Array
      obj.each { |item| validate_object(item, depth + 1) }
    else
      unless ALLOWED_CLASSES.any? { |klass| obj.is_a?(klass) }
        raise "不正なオブジェクトタイプ: #{obj.class}"
      end
    end
  end

  private

  def validate_key(key)
    unless key.is_a?(String)
      raise "キーは文字列である必要があります"
    end

    if key.length > 100
      raise "キーが長すぎます"
    end
  end
end

一般的な脆弱性と対策方法

主な脆弱性とその対策について説明します:

  1. JSONインジェクション対策
class JSONSanitizer
  def sanitize_input(json_string)
    # 制御文字の削除
    cleaned = json_string.gsub(/[\x00-\x08\x0B\x0C\x0E-\x1F]/, '')

    # UTF-8の検証
    unless cleaned.force_encoding('UTF-8').valid_encoding?
      raise "不正なエンコーディング"
    end

    cleaned
  end

  def safe_generate(data)
    JSON.generate(data, 
      ascii_only: true,    # ASCII文字のみ使用
      max_nesting: 20,     # ネストの制限
      allow_nan: false     # NaN, Infinity を禁止
    )
  end
end

セキュリティ対策チェックリスト:

チェック項目対策方法重要度
入力サイズ制限MAX_SIZEの設定
ネスト制限max_nestingの指定
型チェックALLOWED_CLASSESの定義
エンコーディングUTF-8の検証
シリアライズallow_nan: false
  1. セキュアなデシリアライズ処理
module SecureJSONProcessor
  class << self
    def load_json(json_string)
      # 事前検証
      validate_json_syntax(json_string)

      # 安全なパース
      parsed = JSON.parse(json_string, 
        create_additions: false,  # オブジェクト生成を無効化
        symbolize_names: true     # シンボルキーを使用
      )

      # パース後の検証
      validate_parsed_data(parsed)

      parsed
    end

    private

    def validate_json_syntax(json_string)
      # JSON文法の検証
      JSON.parse(json_string)
    rescue JSON::ParserError => e
      raise SecurityError, "不正なJSON構文: #{e.message}"
    end

    def validate_parsed_data(data)
      case data
      when Hash
        data.each do |k, v|
          validate_key(k)
          validate_parsed_data(v)
        end
      when Array
        data.each { |item| validate_parsed_data(item) }
      else
        validate_value(data)
      end
    end

    def validate_key(key)
      if key.to_s.length > 100
        raise SecurityError, "キーが長すぎます"
      end
    end

    def validate_value(value)
      unless [String, Integer, Float, TrueClass, FalseClass, NilClass].any? { |type| value.is_a?(type) }
        raise SecurityError, "不正な値の型: #{value.class}"
      end
    end
  end
end

これらのセキュリティ対策を適切に実装することで、安全なJSONパース処理を実現できます。

実践的なユースケース集

Web APIからの応答処理の実装例

RESTful APIでの実践的なJSONデータ処理方法を解説します:

  1. APIクライアントの実装
require 'net/http'
require 'uri'

class APIClient
  def initialize(base_url)
    @base_url = base_url
  end

  def fetch_data(endpoint, params = {})
    uri = URI.join(@base_url, endpoint)
    uri.query = URI.encode_www_form(params)

    response = Net::HTTP.get_response(uri)
    handle_response(response)
  end

  private

  def handle_response(response)
    case response
    when Net::HTTPSuccess
      parse_response(response.body)
    when Net::HTTPUnauthorized
      raise "認証エラー"
    when Net::HTTPNotFound
      raise "リソースが見つかりません"
    else
      raise "APIエラー: #{response.code}"
    end
  end

  def parse_response(body)
    JSON.parse(body, symbolize_names: true)
  rescue JSON::ParserError => e
    raise "JSONパースエラー: #{e.message}"
  end
end

# 使用例
client = APIClient.new('https://api.example.com')
users = client.fetch_data('/users', {page: 1, per_page: 10})
  1. Webフックの処理
class WebhookProcessor
  def process_webhook(request)
    # リクエストボディの取得と検証
    payload = validate_webhook_payload(request.raw_post)

    # イベントタイプに基づく処理
    case payload[:event_type]
    when 'user.created'
      process_user_creation(payload[:data])
    when 'order.updated'
      process_order_update(payload[:data])
    else
      raise "未知のイベントタイプ: #{payload[:event_type]}"
    end
  end

  private

  def validate_webhook_payload(raw_payload)
    # ペイロードのパースと検証
    payload = JSON.parse(raw_payload, symbolize_names: true)

    unless payload[:event_type] && payload[:data]
      raise "不正なペイロード形式"
    end

    payload
  end

  def process_user_creation(user_data)
    User.create!(
      email: user_data[:email],
      name: user_data[:name],
      role: user_data[:role]
    )
  end

  def process_order_update(order_data)
    order = Order.find(order_data[:id])
    order.update!(
      status: order_data[:status],
      updated_at: Time.parse(order_data[:updated_at])
    )
  end
end

設定ファイルとしてのJSON活用方法

アプリケーションの設定管理におけるJSONの活用例を紹介します:

  1. 階層的な設定管理
class ConfigManager
  def initialize(config_path)
    @config_path = config_path
    @config = load_config
  end

  def load_config
    JSON.parse(File.read(@config_path), symbolize_names: true)
  rescue Errno::ENOENT
    raise "設定ファイルが見つかりません: #{@config_path}"
  rescue JSON::ParserError => e
    raise "設定ファイルの形式が不正です: #{e.message}"
  end

  def get(key_path)
    keys = key_path.to_s.split('.')
    keys.reduce(@config) { |config, key| config[key.to_sym] }
  rescue NoMethodError
    raise "設定が見つかりません: #{key_path}"
  end
end

# 設定ファイルの例(config.json)
{
  "database": {
    "host": "localhost",
    "port": 5432,
    "credentials": {
      "username": "admin",
      "password": "secure_password"
    }
  },
  "api": {
    "endpoint": "https://api.example.com",
    "timeout": 30,
    "retry": {
      "max_attempts": 3,
      "delay": 5
    }
  }
}

# 使用例
config = ConfigManager.new('config.json')
db_host = config.get('database.host')
api_timeout = config.get('api.timeout')
  1. 環境別設定の管理
class EnvironmentConfig
  def initialize(env = ENV['RACK_ENV'])
    @env = env || 'development'
    @config = load_environment_config
  end

  def load_environment_config
    base_config = load_json_file('config/base.json')
    env_config = load_json_file("config/#{@env}.json")

    deep_merge(base_config, env_config)
  end

  private

  def load_json_file(path)
    JSON.parse(File.read(path), symbolize_names: true)
  rescue Errno::ENOENT
    {}
  end

  def deep_merge(hash1, hash2)
    hash1.merge(hash2) do |_, val1, val2|
      if val1.is_a?(Hash) && val2.is_a?(Hash)
        deep_merge(val1, val2)
      else
        val2
      end
    end
  end
end

実践的なユースケース一覧:

ユースケース主な機能利点
API通信データの送受信標準的なデータ形式
Webhookイベント処理非同期通信が可能
設定管理アプリケーション設定階層的な管理が容易
キャッシュデータの一時保存シリアライズが簡単

これらの実装例を参考に、プロジェクトの要件に応じた最適なJSON処理を実現できます。