Class: AtomicsResource::Base

Inherits:
Object
  • Object
show all
Extended by:
ActiveModel::Naming
Defined in:
lib/atomics_resource/base.rb

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attributes = {}) ⇒ Base

Constructor allows hash as arg to set attributes.



181
182
183
184
185
# File 'lib/atomics_resource/base.rb', line 181

def initialize(attributes = {})
  hsh = {}
  @attributes = hsh.respond_to?(:with_indifferent_access) ? hsh.with_indifferent_access : hsh
  load(attributes)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_symbol, *arguments) ⇒ Object

Get attributes as methods, like active_model.



212
213
214
215
216
217
218
219
220
221
222
# File 'lib/atomics_resource/base.rb', line 212

def method_missing(method_symbol, *arguments)
  method_name = method_symbol.to_s
  if method_name =~ /=$/
    attributes[$`] = arguments.first
  elsif method_name =~ /\?$/
    attributes[$`]
  else
    return attributes[method_name] if attributes.include?(method_name)
    super
  end
end

Class Attribute Details

.atomics_typeObject

Returns the value of attribute atomics_type.



16
17
18
# File 'lib/atomics_resource/base.rb', line 16

def atomics_type
  @atomics_type
end

.primary_keyObject

Returns the value of attribute primary_key.



16
17
18
# File 'lib/atomics_resource/base.rb', line 16

def primary_key
  @primary_key
end

.table_nameObject

Returns the value of attribute table_name.



16
17
18
# File 'lib/atomics_resource/base.rb', line 16

def table_name
  @table_name
end

Instance Attribute Details

#attributesObject

instance variables



178
179
180
# File 'lib/atomics_resource/base.rb', line 178

def attributes
  @attributes
end

Class Method Details

.all(*args) ⇒ Object

Calls find and returns array of all matches.



93
94
95
# File 'lib/atomics_resource/base.rb', line 93

def self.all(*args)
  find(:all, *args)
end

.column(value) ⇒ Object

Add a column.



28
29
30
# File 'lib/atomics_resource/base.rb', line 28

def self.column(value)
  columns << value
end

.columnsObject

Get method for array of columns (attr_accessor will break for arrays on inheritance).



23
24
25
# File 'lib/atomics_resource/base.rb', line 23

def self.columns
  @columns ||= []
end

.columns_or_defaultObject

Return array of columns to use for SELECT statements, ensuring we get primary_key, or single string ‘*’ if no columns set.



123
124
125
# File 'lib/atomics_resource/base.rb', line 123

def self.columns_or_default
  columns.empty? ? '*' : ([primary_key]+columns).uniq
end

.construct_sql(options) ⇒ Object

Build a SQL query string from hash of options passed to find.



39
40
41
42
43
44
45
46
47
48
# File 'lib/atomics_resource/base.rb', line 39

def self.construct_sql(options)
  sql = []
  sql << "SELECT "   + construct_sql_for_params(options[:select])
  sql << "FROM "     + construct_sql_for_params(options[:from])
  sql << "WHERE "    + construct_sql_for_conditions(options[:conditions]) if options[:conditions]
  sql << "ORDER BY " + construct_sql_for_params(options[:order]) if options[:order]
  sql << "LIMIT "    + options[:limit].to_s  if options[:limit]
  sql << "OFFSET "   + options[:offset].to_s if options[:offset]
  sql.join(' ')
end

.construct_sql_for_array(a) ⇒ Object

Construct string of conditions from an array of format plus values to substitute. Examples:

[ 'foo = ? AND bar = ?', 'hello', 99 ]
[ 'foo = %s AND bar = %d", 'hello', 99 ]


72
73
74
75
76
77
78
79
80
81
82
# File 'lib/atomics_resource/base.rb', line 72

def self.construct_sql_for_array(a)
  format, *values = a
  if format.include?("\?")
    raise ArgumentError unless format.count('\?') == values.size # sanity check right number args
    format.gsub(/\?/) { quote_value(values.shift.to_s) }         # replace all ? with args
  elsif format.blank?
    format
  else # replace sprintf escapes
    format % values.collect { |value| quote_value(value.to_s) }
  end
end

.construct_sql_for_conditions(option) ⇒ Object

Return string for SQL conditions from options params as string, array, or hash.



60
61
62
63
64
65
66
# File 'lib/atomics_resource/base.rb', line 60

def self.construct_sql_for_conditions(option)
  case option
  when Array; construct_sql_for_array(option)
  when Hash;  construct_sql_for_hash (option) ## :TODO: implement this
  else option
  end
end

.construct_sql_for_hash(h) ⇒ Object

Construct string of conditions from a hash of format plus values to substitute. Allows conditions as hash of key/value pairs to be ANDed together. Examples:

{ :foo => :hello, :bar => 99 }


88
89
90
# File 'lib/atomics_resource/base.rb', line 88

def self.construct_sql_for_hash(h)
  h.map{|k,v| "#{k}=#{quote_value(v.to_s)}"}.join(' AND ')
end

.construct_sql_for_params(parms) ⇒ Object

Return string for SQL conditions from values params as string, array, or hash.



51
52
53
54
55
56
57
# File 'lib/atomics_resource/base.rb', line 51

def self.construct_sql_for_params(parms)
  case parms
  when Array; parms.map(&:to_s).join(',')
  when Hash;  parms.keys.map(&:to_s).join(',')
  else parms.to_s
  end
end

.construct_url_for_sql(sql) ⇒ Object

Return string with whole URL for request, adding given SQL string as query.



142
143
144
145
# File 'lib/atomics_resource/base.rb', line 142

def self.construct_url_for_sql(sql)
  (host, port, path) = ATOMICS_CONFIG[atomics_type.to_s].values_at('host', 'port', 'path')
  "http://#{host}:#{port}#{path}&q=#{URI.escape(sql)}"      
end

.find(*arguments) ⇒ Object

Find takes a list of conditions as a hash, and returns array of matching objects. If single argument is numeric, return first object to match by primary key.



109
110
111
112
113
114
115
116
117
118
119
# File 'lib/atomics_resource/base.rb', line 109

def self.find(*arguments)
  scope   = arguments.slice!(0)
  options = arguments.slice!(0) || {}

  case scope
  when :all   then find_every(options)          # Employee.find(:all,   :conditions => 'team_id = 156')
  when :first then find_every(options).first    # Employee.find(:first, :conditions => 'team_id = 156')
  when :last  then find_every(options).last     # Employee.find(:last,  :conditions => 'team_id = 156')
  else             find_single(scope, options)  # Employee.find(7923113)
  end
end

.find_by_sql(sql) ⇒ Object

Find matches using raw SQL statement given as a string.

args

string containing SQL statement.

returns

array of objects.



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/atomics_resource/base.rb', line 150

def self.find_by_sql(sql)
  url = construct_url_for_sql(sql)

  ## get the xml doc as a nokogiri object
  doc = Nokogiri::XML(open(url))
  

  ## array of records
  records = doc.xpath('//record').to_a.map do |record|
    
    ## convert record into a hash with name => value
    hash = record.xpath('./field').inject({}) do |hash, field|
      hash[field.xpath('./name')[0].content] = field.xpath('./value')[0].content
      hash
    end

    ## instantiate record object
    new(hash)
  end

end

.find_every(options) ⇒ Object

Find array of all matching records.



128
129
130
131
132
# File 'lib/atomics_resource/base.rb', line 128

def self.find_every(options)
  defaults = { :select => columns_or_default, :from => table_name }
  sql = construct_sql(defaults.merge(options))
  find_by_sql(sql)
end

.find_single(scope, options) ⇒ Object

Find a single record with given primary key.



135
136
137
138
139
# File 'lib/atomics_resource/base.rb', line 135

def self.find_single(scope, options)
  defaults = { :select => columns_or_default, :from => table_name, :conditions => {primary_key => scope} }
  sql = construct_sql(defaults)
  find_by_sql(sql).first
end

.first(*args) ⇒ Object

Calls find and returns first matching object.



98
99
100
# File 'lib/atomics_resource/base.rb', line 98

def self.first(*args)
  find(:first, *args)
end

.last(*args) ⇒ Object

Calls find and returns last matching object.



103
104
105
# File 'lib/atomics_resource/base.rb', line 103

def self.last(*args)
  find(:last, *args)
end

.quote_value(value) ⇒ Object

Quote value for Atomics in SQL statment; numeric arguments returned unquoted, strings in single quotes.



34
35
36
# File 'lib/atomics_resource/base.rb', line 34

def self.quote_value(value)
  value.match(/^\d+$/) ? value : "'#{value}'"
end

.to_modelObject

What uses this?



173
174
175
# File 'lib/atomics_resource/base.rb', line 173

def self.to_model
  self
end

Instance Method Details

#[](attr) ⇒ Object

Get attributes using hash syntax.



225
226
227
# File 'lib/atomics_resource/base.rb', line 225

def [](attr)
  attributes[attr]
end

#idObject

Value of primary key.



230
231
232
# File 'lib/atomics_resource/base.rb', line 230

def id
  attributes[self.class.primary_key].to_i
end

#inspectObject

Return formatted inspection string for record with attributes listed.



197
198
199
200
# File 'lib/atomics_resource/base.rb', line 197

def inspect
  attributes_string = @attributes.map{|k,v| "#{k}: #{value_for_inspect(v)}"}.join(', ')
  "#<#{self.class} #{attributes_string}>"
end

#load(attributes) ⇒ Object

Set attributes for an existing instance of this object.

Raises:

  • (ArgumentError)


188
189
190
191
192
193
194
# File 'lib/atomics_resource/base.rb', line 188

def load(attributes)
  raise ArgumentError, "expected an attributes Hash, got #{attributes.inspect}" unless attributes.is_a?(Hash)
  attributes.each do |key, value|
    @attributes[key.to_s] = value.dup rescue value
  end
  self
end

#to_keyObject

What uses this?



235
236
237
# File 'lib/atomics_resource/base.rb', line 235

def to_key
  [id]
end

#to_paramObject

Return primary_key as param for object, for polymorphic route generation to work from object in view.



240
241
242
# File 'lib/atomics_resource/base.rb', line 240

def to_param
  attributes[self.class.primary_key]
end

#value_for_inspect(value) ⇒ Object

Returns inspect for a value, with strings shortened to 50 chars, for use in Object.inspect.



203
204
205
206
207
208
209
# File 'lib/atomics_resource/base.rb', line 203

def value_for_inspect(value)
  if value.is_a?(String) && value.length > 50
    "#{value[0..50]}...".inspect
  else
    value.inspect
  end
end