0

我正在用 Ruby 为Omeka API 编写一个 API 包装器。API 的一部分是创建一个代表 Omeka 网站上的项目的类。对 API 的 GET 请求返回一个 JSON 对象,我将其转换为哈希(见下文,因为它很长)。我没有让用户浏览长哈希,而是使用Recursive Open Struct gem 来创建访问器方法。例如:

class OmekaItem

  attr_accessor :data

  def initialize(hash)
    @data = RecursiveOpenStruct.new(hash, :recurse_over_arrays => true)
  end

end

假设我已经创建了一个名为的类的实例,item它允许用户像这样访问数据:item.data.iditem.data.modified.

最重要的数据在元素文本数组中。有两种元素文本:“都柏林核心”和“项目类型元数据”。我想为这些字段中的数据创建一个单独的 Open Struct。我就是这样做的:

  class OmekaItem

    attr_accessor :data, :dublin_core, :item_type_metadata

    def initialize(hash)
      @data = RecursiveOpenStruct.new(hash, :recurse_over_arrays => true)

      dublin_core = Hash.new
      item_type_metadata = Hash.new
      @data.element_texts.each do |element_text|
        if element_text.element_set.name == "Dublin Core"
          method_name = element_text.element.name.downcase.gsub(/\s/, '_')
          value       = element_text.text
          dublin_core[method_name] = value
        elsif element_text.element_set.name == "Item Type Metadata"
          method_name = element_text.element.name.downcase.gsub(/\s/, '_')
          value       = element_text.text
          item_type_metadata[method_name] = value
        end
      end

      @dublin_core = RecursiveOpenStruct.new(dublin_core)
      @item_type_metadata = RecursiveOpenStruct.new(item_type_metadata)

    end

  end

现在用户可以通过如下方法调用访问都柏林核心元数据:item.dublin_core.title.

到目前为止一切顺利,但这就是我卡住的地方。该类需要实现一个to_h方法,以原始格式返回带有更改数据的哈希,以便我可以将其传递给 POST 和 PUT 方法。如果有人通过调用来更改数据,item.data.element_text[1].text = "My new data"那么我可以轻松地调用返回哈希的开放结构上的方法。但是,如果用户更改item.dublin_core.title = "My new title"该数据将与存储在@data. 我怎样才能使存储数据的两个地方对齐?


项目的典型哈希如下所示:

>> pp hash
{"id"=>1,
 "url"=>"http://localhost/omeka-2.1-rc1/api/items/1",
 "public"=>true,
 "featured"=>false,
 "added"=>"2013-07-13T04:47:08+00:00",
 "modified"=>"2013-07-14T19:37:45+00:00",
 "item_type"=>
  {"id"=>10,
   "url"=>"http://localhost/omeka-2.1-rc1/api/item_types/10",
   "name"=>"Lesson Plan",
   "resource"=>"item_types"},
 "collection"=>
  {"id"=>1,
   "url"=>"http://localhost/omeka-2.1-rc1/api/collections/1",
   "resource"=>"collections"},
 "owner"=>
  {"id"=>1,
   "url"=>"http://localhost/omeka-2.1-rc1/api/users/1",
   "resource"=>"users"},
 "files"=>
  {"count"=>0,
   "url"=>"http://localhost/omeka-2.1-rc1/api/files?item=1",
   "resource"=>"files"},
 "tags"=>[],
 "element_texts"=>
  [{"html"=>false,
    "text"=>"Item Title",
    "element_set"=>
     {"id"=>1,
      "url"=>"http://localhost/omeka-2.1-rc1/api/element_sets/1",
      "name"=>"Dublin Core",
      "resource"=>"element_sets"},
    "element"=>
     {"id"=>50,
      "url"=>"http://localhost/omeka-2.1-rc1/api/elements/50",
      "name"=>"Title",
      "resource"=>"elements"}},
   {"html"=>false,
    "text"=>"Item Subject",
    "element_set"=>
     {"id"=>1,
      "url"=>"http://localhost/omeka-2.1-rc1/api/element_sets/1",
      "name"=>"Dublin Core",
      "resource"=>"element_sets"},
    "element"=>
     {"id"=>49,
      "url"=>"http://localhost/omeka-2.1-rc1/api/elements/49",
      "name"=>"Subject",
      "resource"=>"elements"}},
   {"html"=>false,
    "text"=>"Item Contributor",
    "element_set"=>
     {"id"=>1,
      "url"=>"http://localhost/omeka-2.1-rc1/api/element_sets/1",
      "name"=>"Dublin Core",
      "resource"=>"element_sets"},
    "element"=>
     {"id"=>37,
      "url"=>"http://localhost/omeka-2.1-rc1/api/elements/37",
      "name"=>"Contributor",
      "resource"=>"elements"}},
   {"html"=>true,
    "text"=>"Item Description",
    "element_set"=>
     {"id"=>1,
      "url"=>"http://localhost/omeka-2.1-rc1/api/element_sets/1",
      "name"=>"Dublin Core",
      "resource"=>"element_sets"},
    "element"=>
     {"id"=>41,
      "url"=>"http://localhost/omeka-2.1-rc1/api/elements/41",
      "name"=>"Description",
      "resource"=>"elements"}},
   {"html"=>true,
    "text"=>"Item Creator",
    "element_set"=>
     {"id"=>1,
      "url"=>"http://localhost/omeka-2.1-rc1/api/element_sets/1",
      "name"=>"Dublin Core",
      "resource"=>"element_sets"},
    "element"=>
     {"id"=>39,
      "url"=>"http://localhost/omeka-2.1-rc1/api/elements/39",
      "name"=>"Creator",
      "resource"=>"elements"}},
   {"html"=>false,
    "text"=>"Item Source",
    "element_set"=>
     {"id"=>1,
      "url"=>"http://localhost/omeka-2.1-rc1/api/element_sets/1",
      "name"=>"Dublin Core",
      "resource"=>"element_sets"},
    "element"=>
     {"id"=>48,
      "url"=>"http://localhost/omeka-2.1-rc1/api/elements/48",
      "name"=>"Source",
      "resource"=>"elements"}},
   {"html"=>false,
    "text"=>"Item Publisher",
    "element_set"=>
     {"id"=>1,
      "url"=>"http://localhost/omeka-2.1-rc1/api/element_sets/1",
      "name"=>"Dublin Core",
      "resource"=>"element_sets"},
    "element"=>
     {"id"=>45,
      "url"=>"http://localhost/omeka-2.1-rc1/api/elements/45",
      "name"=>"Publisher",
      "resource"=>"elements"}},
   {"html"=>false,
    "text"=>"Item Date",
    "element_set"=>
     {"id"=>1,
      "url"=>"http://localhost/omeka-2.1-rc1/api/element_sets/1",
      "name"=>"Dublin Core",
      "resource"=>"element_sets"},
    "element"=>
     {"id"=>40,
      "url"=>"http://localhost/omeka-2.1-rc1/api/elements/40",
      "name"=>"Date",
      "resource"=>"elements"}},
   {"html"=>false,
    "text"=>"Item Rights",
    "element_set"=>
     {"id"=>1,
      "url"=>"http://localhost/omeka-2.1-rc1/api/element_sets/1",
      "name"=>"Dublin Core",
      "resource"=>"element_sets"},
    "element"=>
     {"id"=>47,
      "url"=>"http://localhost/omeka-2.1-rc1/api/elements/47",
      "name"=>"Rights",
      "resource"=>"elements"}},
   {"html"=>false,
    "text"=>"Item Relation",
    "element_set"=>
     {"id"=>1,
      "url"=>"http://localhost/omeka-2.1-rc1/api/element_sets/1",
      "name"=>"Dublin Core",
      "resource"=>"element_sets"},
    "element"=>
     {"id"=>46,
      "url"=>"http://localhost/omeka-2.1-rc1/api/elements/46",
      "name"=>"Relation",
      "resource"=>"elements"}},
   {"html"=>false,
    "text"=>"Item Format",
    "element_set"=>
     {"id"=>1,
      "url"=>"http://localhost/omeka-2.1-rc1/api/element_sets/1",
      "name"=>"Dublin Core",
      "resource"=>"element_sets"},
    "element"=>
     {"id"=>42,
      "url"=>"http://localhost/omeka-2.1-rc1/api/elements/42",
      "name"=>"Format",
      "resource"=>"elements"}},
   {"html"=>false,
    "text"=>"Item Language",
    "element_set"=>
     {"id"=>1,
      "url"=>"http://localhost/omeka-2.1-rc1/api/element_sets/1",
      "name"=>"Dublin Core",
      "resource"=>"element_sets"},
    "element"=>
     {"id"=>44,
      "url"=>"http://localhost/omeka-2.1-rc1/api/elements/44",
      "name"=>"Language",
      "resource"=>"elements"}},
   {"html"=>false,
    "text"=>"Item Type",
    "element_set"=>
     {"id"=>1,
      "url"=>"http://localhost/omeka-2.1-rc1/api/element_sets/1",
      "name"=>"Dublin Core",
      "resource"=>"element_sets"},
    "element"=>
     {"id"=>51,
      "url"=>"http://localhost/omeka-2.1-rc1/api/elements/51",
      "name"=>"Type",
      "resource"=>"elements"}},
   {"html"=>false,
    "text"=>"Item Identifier",
    "element_set"=>
     {"id"=>1,
      "url"=>"http://localhost/omeka-2.1-rc1/api/element_sets/1",
      "name"=>"Dublin Core",
      "resource"=>"element_sets"},
    "element"=>
     {"id"=>43,
      "url"=>"http://localhost/omeka-2.1-rc1/api/elements/43",
      "name"=>"Identifier",
      "resource"=>"elements"}},
   {"html"=>false,
    "text"=>"Item Coverage",
    "element_set"=>
     {"id"=>1,
      "url"=>"http://localhost/omeka-2.1-rc1/api/element_sets/1",
      "name"=>"Dublin Core",
      "resource"=>"element_sets"},
    "element"=>
     {"id"=>38,
      "url"=>"http://localhost/omeka-2.1-rc1/api/elements/38",
      "name"=>"Coverage",
      "resource"=>"elements"}},
   {"html"=>false,
    "text"=>"Item Type Duration",
    "element_set"=>
     {"id"=>3,
      "url"=>"http://localhost/omeka-2.1-rc1/api/element_sets/3",
      "name"=>"Item Type Metadata",
      "resource"=>"element_sets"},
    "element"=>
     {"id"=>11,
      "url"=>"http://localhost/omeka-2.1-rc1/api/elements/11",
      "name"=>"Duration",
      "resource"=>"elements"}},
   {"html"=>false,
    "text"=>"Item Type Standards",
    "element_set"=>
     {"id"=>3,
      "url"=>"http://localhost/omeka-2.1-rc1/api/element_sets/3",
      "name"=>"Item Type Metadata",
      "resource"=>"element_sets"},
    "element"=>
     {"id"=>24,
      "url"=>"http://localhost/omeka-2.1-rc1/api/elements/24",
      "name"=>"Standards",
      "resource"=>"elements"}},
   {"html"=>false,
    "text"=>"Item Type Objectives",
    "element_set"=>
     {"id"=>3,
      "url"=>"http://localhost/omeka-2.1-rc1/api/element_sets/3",
      "name"=>"Item Type Metadata",
      "resource"=>"element_sets"},
    "element"=>
     {"id"=>25,
      "url"=>"http://localhost/omeka-2.1-rc1/api/elements/25",
      "name"=>"Objectives",
      "resource"=>"elements"}},
   {"html"=>false,
    "text"=>"Item Type Materials",
    "element_set"=>
     {"id"=>3,
      "url"=>"http://localhost/omeka-2.1-rc1/api/element_sets/3",
      "name"=>"Item Type Metadata",
      "resource"=>"element_sets"},
    "element"=>
     {"id"=>26,
      "url"=>"http://localhost/omeka-2.1-rc1/api/elements/26",
      "name"=>"Materials",
      "resource"=>"elements"}},
   {"html"=>false,
    "text"=>"Item Type Lesson Plan Text",
    "element_set"=>
     {"id"=>3,
      "url"=>"http://localhost/omeka-2.1-rc1/api/element_sets/3",
      "name"=>"Item Type Metadata",
      "resource"=>"element_sets"},
    "element"=>
     {"id"=>27,
      "url"=>"http://localhost/omeka-2.1-rc1/api/elements/27",
      "name"=>"Lesson Plan Text",
      "resource"=>"elements"}}],
 "extended_resources"=>[]}
4

1 回答 1

1

这就是我最终做的。它使用 Ruby 的一些元编程方法来循环遍历元素文本,并为每个文本创建方法。我不知道真正有帮助的两件事是这些。首先,循环遍历数组each_with_index让我得到数组中项目的索引,这是创建访问器方法所必需的。其次,我学会了如何将值传递给 proc;请参阅 setter 方法。

  class OmekaItem

    attr_accessor :data

    # Parse the data we got from the API into handy methods. All of the data
    # from the JSON returned by the API is available as RecursiveOpenStructs
    # through @data. The Dublin Core and Item Type Metadata fields are also
    # available though special methods of the form dc_title and itm_field.
    #
    # @param  hash [Hash] Uses the hash from OmekaClient::Client::get_hash
    #
    def initialize(hash)
      @data = RecursiveOpenStruct.new(hash, :recurse_over_arrays => true)

      # Step through the element texts separating them into Dublin Core and
      # Item Type Metadata elements. e is the element text hash; i is the
      # index of the element_text in the array of element texts.
      @data.element_texts.each_with_index do |e, i|
        if e.element_set.name == "Dublin Core"
          # Define a reader method that retrieves the data from this element
          # text in @data
          self.class.send(:define_method,
            # The name of the method will have the form "dc_title"
            e.element.name.downcase.gsub(/^/, 'dc_').gsub(/\s/, '_'),
            proc{ @data.element_texts[i].text }
            )
          # Define a setter method that sets the data for this element text in
          # @ data
          self.class.send(:define_method,
            # The name of the method will have the form "dc_title="
            e.element.name.downcase.gsub(/^/, 'dc_').gsub(/\s/, '_').gsub(/$/, '='),
            proc{ |value| @data.element_texts[i].text = value }
            )
        elsif e.element_set.name == "Item Type Metadata"
          # Define a reader method that retrieves the data from this element
          # text in @data
          self.class.send(:define_method,
            # The name of the method will have the form "itm_field"
            e.element.name.downcase.gsub(/^/, 'itm_').gsub(/\s/, '_'),
            proc{ @data.element_texts[i].text }
            )
          # Define a setter method that sets the data for this element text in
          # @ data
          self.class.send(:define_method,
            # The name of the method will have the form "itm_title="
            e.element.name.downcase.gsub(/^/, 'itm_').gsub(/\s/, '_').gsub(/$/, '='),
            proc{ |value| @data.element_texts[i].text = value }
            )
        end
      end

    end

  end
于 2013-08-01T21:02:45.870 回答