Module: Sheety::Children::ClassMethods

Defined in:
lib/sheety/children.rb

Instance Method Summary collapse

Instance Method Details

#atom_children(symbol, options) ⇒ Object

Defines a child relationship with the given name symbol (required): the name of the child options (required): a hash of options

- klass (required): the class to use for the child instances
- link (required): the url to fetch the children from
-


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/sheety/children.rb', line 36

def atom_children(symbol, options)

  if options.blank?
    raise ArgumentError.new("blank options #{options} are not valid options for atom_children")
  end

  if options[:klass].blank? || options[:klass].class != Class
    raise ArgumentError.new("#{options} must have a :klass that is a Class, not a #{options[:klass].class}")
  end

  if options[:link].blank?
    raise ArgumentError.new("#{options} must have a non-blank :link")
  end

  unless method_defined?(:link)
    raise TypeError.new("#{self} must respond to :link to use atom_children")
  end

  if options[:merge_links] && method_defined?(:add_links) == false
    raise TypeError.new("#{self} must respond to :add_links in atom_children with merge_links=true")
  end

  plural = symbol.to_s
  singular = plural.singularize

  inst_var_sym = :"@#{symbol}"

  get_method = :"#{plural}"
  new_method = :"new_#{singular}"
  enum_method = :"_enumerate_#{plural}_by_method"
  where_method = :"#{plural}_where"
  except_method = :"#{plural}_except"
  except_any_method = :"#{plural}_except_any"
  find_first_method = :"find_#{singular}"

  # Defines a method that instantiates a new child
  define_method(new_method) do |entry=nil|
    options[:klass].new(self, entry)
  end

  # Defines a method that fetches children from Google
  define_method(get_method) do |force_refetch=false|
    if instance_variable_get(inst_var_sym).nil? || force_refetch
      list = Sheety::Api.inst.get_feed(link(options[:link])) # sort of a cyclic dependency, suboptimal

      if list.nil?
        raise Sheety::SheetyFetchError.new, "Fetching #{plural} failed!"
      end

      # TODO: Create a ListFeed Object so the links we get here don't need to be worried about collisions on link ids
      add_links(list['link']) if !list['link'].blank? && options[:merge_links]

      list = (list['entry'] || []).map do |entry|
        method(new_method).call(entry)
      end

      instance_variable_set(inst_var_sym, list)
    end

    return instance_variable_get(inst_var_sym)
  end

  # Defines a helper-method that will iterate over children checking that each item passes all constraints given
  define_method(enum_method) do |constraints, enumeration_method|
    children = method(get_method).()

    if children.nil?
      return []
    end

    return children.send(enumeration_method) do |item|
      constraints.all? do |constraint|
        _passes_constraint(_get_i_val(item, constraint[0], options[:accessor]), constraint[1])
      end
    end
  end

  # Defines a method that selects the children who adhere to all constraints given
  define_method(where_method) do |constraints|
    return method(enum_method).call(constraints, :find_all)
  end

  # Defines a method that selects the first child that passes all constraints given
  define_method(find_first_method) do |constraints|
    return method(enum_method).call(constraints, :detect)
  end

  # Defines a method that selects those children who fail to meet all constraint given
  define_method(except_method) do |constraints|
    return method(enum_method).call(constraints, :reject)
  end

  # Defines a method that selects those children who fail to meet at least one constraint given
  define_method(except_any_method) do |constraints|
    children = method(get_method).()

    if children.nil?
      return []
    end

    return children.reject do |item|
      constraints.any? do |constraint|
        _passes_constraint(_get_i_val(item, constraint[0], options[:accessor]), constraint[1])
      end
    end
  end
end