代码之家  ›  专栏  ›  技术社区  ›  t56k

Ruby 2.4/Rails 5:生成递归哈希数组,如果键为空则删除

  •  0
  • t56k  · 技术社区  · 7 年前

    我有一个类似这样的类,它将集合转换为哈希的嵌套数组:

    # variable_stack.rb
    class VariableStack
      def initialize(document)
        @document = document
      end
    
      def to_a
        @document.template.stacks.map { |stack| stack_hash(stack) }
      end
    
      private
    
      def stack_hash(stack)
        {}.tap do |hash|
          hash['stack_name'] = stack.name.downcase.parameterize.underscore
          hash['direction'] = stack.direction
          hash['boxes'] = stack.boxes.indexed.map do |box|
            box_hash(box)
          end.reverse_if(stack.direction == 'up') # array extensions
        end.delete_if_key_blank(:boxes) # hash extensions
      end
    
      def box_hash(box)
        {}.tap do |hash|
          hash['box'] = box.name.downcase.parameterize.underscore
          hash['content'] = box.template_variables.indexed.map do |var|
            content_array(var)
          end.join_if_any?
        end.delete_if_key_blank(:content)
      end
    
      def content_array(var)
        v = @document.template_variables.where(master_id: var.id).first
        return unless v
        if v.text.present?
          v.text
        elsif v.photo_id.present?
          v.image.uploaded_image.url
        else
          ''
        end
      end
    end
    
    # array_extensions.rb
    class Array
      def join_if_any?
        join("\n") if size.positive?
      end
    
      def reverse_if(boolean)
        reverse! if boolean
      end
    end
    
    # hash_extensions.rb
    class Hash
      def delete_if_key_blank(key)
        delete_if { |_, _| key.to_s.blank? }
      end
    end
    

    该方法应该返回如下所示的哈希:

    "stacks": [
    {
      "stack_name": "stack1",
      "direction": "down",
      "boxes": [
        {
          "box": "user_information",
          "content": "This is my name.\n\nThis is my phone."
        }
    },
    {
      "stack_name": "stack2",
      "direction": "up",
      "boxes": [
        {
          "box": "fine_print",
          "content": "This is a test.\n\nYeah yeah."
        }
      ]
    }
    

    相反,box键通常为null:

    "stacks": [
    {
      "stack_name": "stack1",
      "direction": "down",
      "boxes": null
    },
    {
      "stack_name": "stack2",
      "direction": "up",
      "boxes": [
        {
          "box": "fine_print",
          "content": "This is a test.\n\nYeah yeah."
        }
      ]
    }
    

    我怀疑这是因为我无法在Rails 5中“单行”添加阵列(即,它们被冻结)。这个 @document.template.stacks 是ActiveRecord集合。

    hash['boxes'] ?

    失败的测试

    APIDocumentV3 Instance methods #stacks has the correct content joined and indexed
     Failure/Error:
       expect(subject.stacks.first['boxes'].first['content'])
         .to include(document.template_variables.first.text)
    
       expected "\n" to include "#1"
       Diff:
       @@ -1,2 +1 @@
       -#1
    

    存在 \n

    2 回复  |  直到 7 年前
        1
  •  1
  •   Danil Speransky    7 年前

    reverse_if 退货 nil 如果条件为假。考虑一下:

    [] if false #=> nil
    

    你可以这样改变它:

    def reverse_if(condition)
      condition ? reverse : self
    end
    

    delete_if_key_blank 对我来说不太好。它从不删除任何内容。

    免责声明我认为扩展标准库不是一个好主意。

        2
  •  0
  •   t56k    7 年前

    多亏了丹尼尔·斯佩兰斯基,我解决了这个问题,尽管他写的东西并没有完全涵盖这个问题。

    nil 具有以下代码的数组:

    hash['boxes'] = stack.boxes.indexed.map do |box|
        box_hash(box) unless box_hash(box)['content'].blank?
      end.reverse_if(stack.direction == 'up').delete_if_blank?
    end
    

    .delete_if_blank? Array 上课一点帮助都没有。看起来是这样的,仅供参考:

    class Array
      def delete_if_blank?
        delete_if(&:blank?)
      end
    end
    

    我通过使用 unless box_hash(box)['content'].blank?