ruby中的递归哈希转换函数

2024-01-11

我有以下响应模式的 swagger (openAPI) 定义:

h = { "type"=>"object",
      "properties"=>{
        "books"=>{
          "type"=>"array",
          "items"=>{
            "type"=>"object",
            "properties"=>{
              "urn"  =>{ "type"=>"string" },
              "title"=>{ "type"=>"string" }
            }
          }
        }
      }
    }

并希望将其转换为以下格式,以便能够将此响应显示为树:

{ "name"=>"200",
  "children"=> [
    {
      "name"=>"books (array)",
      "children"=> [
        {"name"=>"urn (string)" },
        {"name"=>"title (string)" }
      ]
    }
  ]
}

在 swagger 模式格式中,节点可以是一个对象(带有属性),也可以是一个项目数组,这些项目本身就是对象。这是我编写的函数:schema参数是上面所示的swagger格式的散列,树变量包含{name: "200"}

      def build_tree(schema, tree)
        if schema.class == ActiveSupport::HashWithIndifferentAccess
          case schema[:type]
          when 'object'
            tree[:children] = []
            schema[:properties].each do |property_name, property_schema|
               tree[:children] <<
                 { name: property_name, children: build_tree(property_schema, tree) }
            end
          when 'array'
            schema[:items].each do |property_name, property_schema|
              tree[:children] <<
                { name: property_name, children: build_tree(property_schema, tree) }
            end
          when nil
            tree[:name] == schema
          end
          else
            tree[:name] == schema
          end
        end

不幸的是,我认为我在某个地方犯了错误,因为这返回了以下哈希:

{ :name=>"200",
  :children=>[
    { :name=>"type", :children=>false },
    { :name=>"properties", :children=>false },
    { :name=>"books",
      :children=>{
        "type"=>"object",
        "properties"=>{
          "urn"=>{"type"=>"string"},
          "title"=>{"type"=>"string"}
        }
      }
    }
  ]
}

我一定是在递归中错过了一个步骤,或者以错误的方式传递了树,但我担心我没有足够的脑力来弄清楚:)也许一个有编写漂亮的 ruby​​ 代码天赋的善良灵魂会给出我一手!


因此,项目数组不是项目数组,而是子模式的属性数组。这是考虑到这一事实的新解决方案:

schema = 
    { "type"=>"object",
      "properties"=>{
        "books"=>{
          "type"=>"array",
          "items"=> {
              "type"=>"object",
              "properties" => {
                "urn"   => { "type"=>"string" },
                "title" => { "type"=>"string" }
                              }
          } # end items
        } # end books
      } # end properties
    } # end schema

tree = {"name"=>"200"}

def build_tree(schema, tree, level)
    puts
    puts "level=#{level} schema[:type]=#{schema['type'].inspect}, schema class is #{schema.class}"
    puts "level=#{level} tree=#{tree}"
    case schema['type']
    when 'object'
        puts "in when object for #{schema['properties'].size} properties :"
        i = 0
        schema['properties'].each_key{ | name | puts "#{i+=1}. #{name}" }
        tree[:children] = []
        schema['properties'].each do | property_name, property_schema |
            puts "object level=#{level}, property_name=#{property_name}"
            type, sub_tree = build_tree(property_schema, {}, level + 1)
            puts "object level=#{level} after recursion, type=#{type} sub_tree=#{sub_tree}"
            child = { name: property_name + type }
            sub_tree.each { | k, v | child[k] = v }
            tree[:children] << child
        end
        puts "object level=#{level} about to return tree=#{tree}"
        tree
    when 'array'
        puts "in when array"
        case schema['items']
        when Hash
            puts "in when Hash"
            puts "the schema has #{schema['items'].keys.size} keys :"
            schema['items'].keys.each{ | key | puts key }
            # here you could raise an error if the two keys are NOT "type"=>"object" and "properties"=>{ ... }
            puts "Hash level=#{level} about to recurs"
            return ' (array)', build_tree(schema['items'], {}, level + 1)
        else
            puts "oops ! Hash expected"
            "oops ! Hash expected"
        end
    when 'string'
        puts "in when string, schema=#{schema}"
        return ' (string)', {}
    else
        puts "in else"
        tree[:name] == schema # ???? comparison ?
    end
end

build_tree(schema, tree, 1)
puts 'final result :'
puts tree

编辑结果(使用 ruby​​ 2.3.3p222 测试):

{ "name"=>"200", 
  :children=> [
    {
      :name=>"books (array)", 
      :children=> [
        {:name=>"urn (string)"}, 
        {:name=>"title (string)"}
      ]
    }
  ]
}

不要将其视为出色的代码。每次 12 级地震我都会编写 Ruby 代码。目的是解释代码中哪些内容不起作用,并引起人们注意在递归调用中使用新变量(现在是空哈希)。有很多情况需要测试并引发错误。

正确的方法是 BDD,就像 @moveson 一样:首先为所有情况(尤其是边缘情况)编写 RSpec 测试,然后编写代码。我知道它给人的感觉是太慢了,但从长远来看,它是值得的,并且取代了跟踪的调试和打印。

有关测试的更多信息

此代码很脆弱:例如,如果类型键未与属性键关联,则它将失败schema['properties'].each : undefined method 'each' for nil:NilClass。像这样的规格context 'when a type object has no properties' do let(:schema) { {"type" => "object", "xyz" => ...

将有助于添加代码来检查先决条件。我也懒得在小脚本中使用 RSpec,但对于严肃的开发,我会付出努力,因为我已经认识到了它的好处。花在调试上的时间就永远消失了,投入在规范上的时间可以在发生变化时提供安全性,并提供关于代码做什么或不做什么的清晰易读的缩进报告。我推荐全新的Rspec 3 本书 https://pragprog.com/book/rspec3/effective-testing-with-rspec-3.

关于访问哈希的更多信息:如果混合使用字符串和符号,则会出现问题。

some_key = some_data # sometimes string, sometimes symbol
schema[some_key]...

如果内部键与外部数据的类型不同,则将找不到该元素。创建哈希时选择一种类型,例如符号,并系统地将访问变量转换为符号:

some_key = some_data # sometimes string, sometimes symbol
schema[some_key.to_sym]...

或全部转为字符串:

some_key = some_data # sometimes string, sometimes symbol
schema[some_key.to_s]...
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ruby中的递归哈希转换函数 的相关文章

  • 在 Ruby 中将 Time 类对象转换为 RFC3339

    谷歌日历 API v2 https developers google com google apps calendar v2 developers guide protocol的时间相关查询需要采用 RFC3339 格式 当我在 需要 时
  • 如何在 Ruby 2.0 中使用调试器?

    我知道调试器 gem 不会也永远不会与 ruby 2 0 per 兼容正式支持ruby 2 X https github com cldwalker debugger issues 47 issuecomment 44027702 Ruby
  • 如何在C中递归地找到另一个字符串中的字符串位置?

    我们有一个任务来创建带有两个字符串参数的递归函数 原型应该是这样的 int instring char word char sentence 如果我们愿意调用函数 instring Word Another Word 它应该具有以下返回值
  • 如何使用 ruby​​zip 库获取压缩文件的内容?

    我正在尝试提取上传的 zip 文件并将其内容存储在数据库中 每个文件一个条目 rubyzip 库几乎没有有用的文档 有一个资产表 其中包含键 string 文件名 和数据 binary 文件内容 我正在使用 ruby zip 库 并且已经做
  • to_proc 方法在 Ruby 中意味着什么?

    我正在学习 Rails 并关注这个线程 https stackoverflow com questions 1961030 我被困住了to proc方法 我认为符号只是字符串的替代品 它们就像字符串 但在内存方面更便宜 如果我还缺少任何其他
  • 这段代码中list[:]的含义是什么? [复制]

    这个问题在这里已经有答案了 这段代码来自Python的文档 我有点困惑 words cat window defenestrate for w in words if len w gt 6 words insert 0 w print wo
  • 使用 ruby​​ Net::SSH 通过 sudo 读取远程文件

    我必须读取我有权 sudo 读取的远程文件的内容 猫 少或尾巴 我将在 Ruby 中执行此操作 因此我认为应该使用 Net SSH 来执行此操作 该文件是一个日志文件 因此可能会很大 这是我现在正在尝试的代码 require rubygem
  • Ruby 多维数组

    也许只是我缺乏在这里找到东西的能力 这就是问题所在 但我找不到任何关于如何在 Ruby 中创建多维数组的信息 有人可以给我一个如何做的例子吗 严格来说 在 Ruby 中创建多维数组是不可能的 但是可以将一个数组放入另一个数组中 这与多维数组
  • 当你不继承Rails 4中的ApplicationController时,如何包含respond_to?

    我在 Rails 4 1 2 应用程序中有一个 API 控制器 它不继承自应用程序控制器 我试图包含 respond to 方法并得到一个方法未定义的错误 所以然后我需要在顶部的操作包 如下所示 require action pack cl
  • 直接或通过包含定义嵌套类

    假设我正在为我的家庭存储系统建模 我有很多不同类型的Container 而且我发现其中很多都有装饰品 因此我为这种常见情况设置了一些辅助代码 我的容器中有我的Mantlepiece and my Bookcase 我只在前者上存放装饰品 而
  • typescript 类型最大递归限制为 9

    我终于成功创建了一个通用类型 它为我提供了 json 键列表 值的所有可能组合 我什至准备了一种限制递归的方法 type EditAction
  • 如何将 STDOUT 捕获到字符串?

    puts hi puts bye 我想存储到目前为止代码的 STDOUT 在本例中 hi nbye 到变量中说 结果 并打印它 puts result 我这样做的原因是我已将 R 代码集成到我的 Ruby 代码中 当 R 代码运行时 其输出
  • Ruby - :variable 和 @variable 之间的区别

    作为 Ruby on Rails 新手 我知道 和 引用具有不同的含义 我看见这个帖子 https stackoverflow com questions 3538575 whats the difference between and v
  • Sublime Text 是否支持 Ruby API(自动完成)?

    如何获取可用于某些对象或类的方法列表 如下所示 Sublime Text 有针对 Ruby 的此功能吗 像这样https github com BoundInCode Display Functions https github com B
  • 生成一定长度的所有排列

    假设我们有一个字母表 abcdefghiklimnop 如何以有效的方式以五个一组的形式重复该字母表来递归生成排列 几天来我一直在为此苦苦挣扎 任何反馈都会有帮助 本质上这与 生成给定字符串的所有排列 https stackoverflow
  • 从轨道控制器返回

    这是一个初学者 Rails 问题 我这样做之后 format xml head ok 如何从控制器端点返回而不显示视图 如果我此时放弃函数的末尾 我会得到我所期望的结果 但如果我调用 返回 我最终会进入视图 或者在我的情况下会出现缺少的视图
  • 如何阻止“gem”实用程序访问我的主目录?

    当我跑步时 gem install
  • 使用 Ruby 通过 Outlook 发送消息的最简单方法是什么?

    我的工作要求我为某些测试自动生成电子邮件 我一直在四处寻找 但一直未能找到可以快速实施的合理解决方案 它需要在 Outlook 中 而不是其他邮件服务器中 因为我们有一些奇怪的身份验证规则 并且我们需要保存草稿的选项 而不仅仅是发送消息 显
  • 如果数组包含一个或多个相同值,则合并数组

    我有一个数组数组 a 1 2 3 3 4 5 6 7 8 8 9 9 10 我想合并包含一个或多个相同值的所有数组 所以 a 1 2 3 4 5 6 7 8 9 10 我正在努力寻找一种简洁的方法来解决这个问题 有任何想法吗 我相信这是正确
  • ActiveRecord 查询,按关联排序,最后一个 has_many

    我试图列出所有Users by the created at最近创建的关联记录 通讯 列 到目前为止我所拥有的 User includes communications order communications created at IS

随机推荐

  • 如何使用 sed 删除与模式匹配的行及其后面的行?

    我有一个看起来像这样的文件 good text good text FLAG bad text bad text good text good text good test bad Text FLAG bad text bad text g
  • 我是否缺少在 Ubuntu 9.04 上使用 Python2.6 绑定构建/安装 VTK-5.4 的步骤?

    我使用源代码的 Python 绑定成功构建并安装了 VTK 5 4 然而 当我尝试在 python 中导入 VTK 时 它给出了以下回溯错误 文件 第 1 行 位于 文件 usr local lib python2 6 dist packa
  • 如何在 swift 3 中将 NSArray 转换为 Swift Array

    我有两个数组 var arr1 NSArray var arr2 String 我想转换NSArray到字符串数组中 我在用 arr2 arr1 作为 细绳 但它给了我错误 NSString is not a subtype of NSAr
  • 在 Python 中将小时和分钟转换为总分钟

    我有一个 Pandas DataFrame 其中有一列以小时和分钟为单位的时间字符串 例如 1 小时 8 分钟 有些单元只有几分钟 例如 47 分钟 我试图从这种格式转换为总分钟数的整数值 例如 1 小时 8 分钟将是 68 我尝试对其进行
  • TFS 2018 Update 2 IIS 网站部署已弃用或缺失

    将 TFS 更新到更新 2 后 在 CI 构建任务中 IIS Web 应用程序部署 被标记为 已弃用 这个任务的替代品是什么 Also in the CD in the after adding IIS Website Deployment
  • Django 无效的块标签:endelse 和 ifequal

    我想使用 djangoifequal and else判断变量是否等于的标签80 or 22 所以 这是代码 if firewalls thead tr th IP address th th Function th tr thead en
  • O(n) 算法找出出现次数超过 n/2 次的元素

    在一次采访中 有人要求我提供一个 O n 算法来打印在数组中出现超过 n 2 次的元素 如果存在这样的元素 n 是数组的大小 我不知道如何做到这一点 有人可以帮忙吗 这是博耶的投票算法 http www cs utexas edu moor
  • 按钮高度不一致(跨浏览器)

    我在设置按钮的高度时遇到问题 基本上我无法跨浏览器使用它 对于 Firefox 它高于normal 没有任何理由 这是一个屏幕截图 Firefox Safari 和 Opera 按此顺序 这里是代码 http jsfiddle net TM
  • 在 iOS 中绘制矩形

    我的应用程序的目标是让用户能够通过向左和向右滑动 iPhone 屏幕来对不同的日程安排选项进行排序 当用户对这些不同的调度选项进行排序时 我将如何绘制和删除矩形 我有一个 UIViewController h UIViewControlle
  • 通过文档文字 SOAP 发送 Base64 图像的替代方案

    我目前正在修改业务应用程序的文档文字 SOAP 服务 该应用程序前后传输有关客户的数据 刚刚确定了传输扫描文档图像的新要求 我遇到的问题是我使用的专有语言不支持 SOAP 附件 传输的图像可以是最大 32KB 的任何图像 我能想到的唯一解决
  • 获取产品的自定义选项值 magento 2

    我的产品有两个自定义选项 颜色和尺寸都是下拉菜单 在产品详细信息页面中 我必须显示该产品的所有可用颜色 我尝试了以下代码并且它有效 但它返回所有颜色和大小的值 但我只需要颜色值 那就是我想按颜色选择自定义选项 product block g
  • 在Windows中,2<&1和2>&1有什么区别?

    本页中的示例和解释让我感到困惑 http www microsoft com resources documentation windows xp all proddocs en us redirection mspx mfr true h
  • 等待 Kotlin 协程在 onCreateView() 中完成

    我有一个初始化块onCreateView 其中一些变量是从 SharedPreferences DB 或 Network 当前从 SharedPreferences 分配的 我想用这些值更新视图onViewCreated 但它们在协程之前更
  • 合并所有两个表但列数不同

    select count as total FROM SELECT FROM database1 orders WHERE number LIKE 11111111111111111 UNION ALL SELECT FROMdatabas
  • 信号会通过哪些方式干扰管道通信?

    我对信号一无所知 对管道也只有一点了解 从评论来看zdim s在这里回答 https stackoverflow com questions 48558093看来信号可能会干扰父进程和子进程之间的管道通信 有人告诉我 如果你使用IO Sel
  • 错误:(24, 11) 无法解析:com.android.support:appcompat-v7:8.0.+

    请帮助解决这个错误 因为这是我的第一个 Android 项目 摇篮同步 应用插件 com android application android compileSdkVersion 8 buildToolsVersion 23 0 2 de
  • 什么是对象切片?

    在 C 中 什么是对象切片以及它何时发生 切片 是将派生类的对象分配给基类的实例 从而丢失部分信息 其中一些信息被 切片 掉 例如 class A int foo class B public A int bar 所以一个类型的对象B有两个
  • Bootstrap 委托弹出内容回调触发两次

    我正在使用 Twitter Bootstrap 2 3 2 并且我正在注册一个弹出窗口 每当带有选择器的 td 悬停在上面时就会打开 但是我注意到在控制台中内容回调被触发两次 有没有办法防止这种情况发生 table data popover
  • Caffe 中的欧几里得损失层

    我目前正在尝试在 caffe 中实现我自己的损失层 在尝试这样做的同时 我使用其他层作为参考 然而 让我困惑的一件事是使用top 0 gt cpu diff in Backward cpu 我将使用EuclideanLossLayer作为参
  • ruby中的递归哈希转换函数

    我有以下响应模式的 swagger openAPI 定义 h type gt object properties gt books gt type gt array items gt type gt object properties gt