atomics_resource 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +22 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +92 -0
- data/Rakefile +51 -0
- data/VERSION +1 -0
- data/examples/employees.rb +37 -0
- data/lib/atomics_resource.rb +30 -0
- data/lib/atomics_resource/base.rb +246 -0
- data/test/helper.rb +7 -0
- data/test/spec_atomics_resource.rb +52 -0
- data/test/test_atomics_resource.rb +7 -0
- metadata +124 -0
data/.document
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
git (1.2.5)
|
5
|
+
jeweler (1.6.4)
|
6
|
+
bundler (~> 1.0)
|
7
|
+
git (>= 1.2.5)
|
8
|
+
rake
|
9
|
+
nokogiri (1.5.0)
|
10
|
+
rake (0.9.2)
|
11
|
+
rcov (0.9.10)
|
12
|
+
shoulda (2.11.3)
|
13
|
+
|
14
|
+
PLATFORMS
|
15
|
+
ruby
|
16
|
+
|
17
|
+
DEPENDENCIES
|
18
|
+
bundler (~> 1.0.0)
|
19
|
+
jeweler (~> 1.6.4)
|
20
|
+
nokogiri
|
21
|
+
rcov
|
22
|
+
shoulda
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Richard Lister
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
= Atomics Resource
|
2
|
+
|
3
|
+
Ruby and/or Rails interface for Atomics queries. Atomics is MySQL over
|
4
|
+
HTTP, originally developed at CNET and has similar intent to DBSlayer.
|
5
|
+
|
6
|
+
== Philosophy
|
7
|
+
|
8
|
+
This module use a different approach from
|
9
|
+
e.g. activerecord-dbslayer-adapter, which subclasses the MySQL adapter
|
10
|
+
in order to use ActiveRecord. Rather, AtomicsResource is a lightweight
|
11
|
+
re-implementation of some ActiveRecord-style methods, which means the
|
12
|
+
module can be used in non-Rails apps, or mixed with non-MySQL
|
13
|
+
connections in a Rails app.
|
14
|
+
|
15
|
+
== Overview
|
16
|
+
|
17
|
+
Classes representing resources in atomics are created by subclassing
|
18
|
+
AtomicsResource::Base. Class find methods are mapped to HTTP GET
|
19
|
+
requests. XML responses are parsed and mapped to an instance of the
|
20
|
+
class.
|
21
|
+
|
22
|
+
=== Configuration
|
23
|
+
|
24
|
+
To use an instance, you will need to create a yaml file with atomics
|
25
|
+
configs, e.g. config/atomics.yml:
|
26
|
+
|
27
|
+
hr:
|
28
|
+
host: hr-atomics.newco.com
|
29
|
+
port: 8080
|
30
|
+
path: /jAtomics/select/?version=1
|
31
|
+
|
32
|
+
then load the file into a hash called ATOMICS_CONFIG; in Rails this is
|
33
|
+
best done from an initializer, e.g. config/initializers/atomics_config.rb:
|
34
|
+
|
35
|
+
ATOMICS_CONFIG = YAML.load_file("#{RAILS_ROOT}/config/atomics.yml")
|
36
|
+
|
37
|
+
=== Usage
|
38
|
+
|
39
|
+
Your model will look like this:
|
40
|
+
|
41
|
+
class Employee < AtomicsResource::Base
|
42
|
+
set_atomics_type :hr #section of config file to read
|
43
|
+
set_table_name :employee_display #default table for requests
|
44
|
+
set_primary_key :id #default key for find() methods
|
45
|
+
|
46
|
+
## default columns to SELECT, if none-given default will be '*'
|
47
|
+
column :first_name
|
48
|
+
column :last_name
|
49
|
+
column :title
|
50
|
+
column :team_id
|
51
|
+
end
|
52
|
+
|
53
|
+
and a simple controller:
|
54
|
+
|
55
|
+
class EmployeesController < ApplicationController
|
56
|
+
def index
|
57
|
+
@employees = Employee.all(:conditions => [ "team_id = ?", params[:team] ]
|
58
|
+
:order => [ :last_name, :first_name ])
|
59
|
+
end
|
60
|
+
|
61
|
+
def show
|
62
|
+
@employee = Employee.find(params[:id])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
Conditions may be given as follows:
|
67
|
+
|
68
|
+
:conditions => "team_id = 156 AND title = 'Manager'"
|
69
|
+
:conditions => [ "team_id = ? AND title = ?", 156, 'Manager' ]
|
70
|
+
:conditions => [ "team_id = %d AND title = %s", 156 , 'Manager' ]
|
71
|
+
:conditions => { :team_id => 156, :title => :Manager }
|
72
|
+
|
73
|
+
Columns: in general you don't want to do "SELECT *" from Atomics
|
74
|
+
tables, which are frequently huge, denormalized beasts which will put
|
75
|
+
a lot of extra data on the wire that you don't want. Instead, list in
|
76
|
+
the model the columns you normally want, using 'column'. These will be
|
77
|
+
used to create the default 'SELECT' statement in find(). This can be
|
78
|
+
overridden using something like find(:all, :select=>'*').
|
79
|
+
|
80
|
+
Convenience functions:
|
81
|
+
|
82
|
+
Employee.all(99) ## equivalent to Employee.find(:all, :conditions => {:id = 99})
|
83
|
+
Employee.first(99) ## equivalent to Employee.find(:first, :conditions => {:id = 99})
|
84
|
+
Employee.last(99) ## equivalent to Employee.find(:last, :conditions => {:id = 99})
|
85
|
+
|
86
|
+
== Contributing to atomics_resource
|
87
|
+
|
88
|
+
The project is available for forking at github.
|
89
|
+
|
90
|
+
== Copyright
|
91
|
+
|
92
|
+
Copyright (c) 2011 Richard Lister. See LICENSE.txt for further details.
|
data/Rakefile
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
gem.name = "atomics_resource"
|
17
|
+
gem.homepage = "http://github.com/rlister/atomics_resource"
|
18
|
+
gem.license = "MIT"
|
19
|
+
gem.summary = %Q{Active Model for Atomics MySQL lookups}
|
20
|
+
gem.description = %Q{Model Atomics (MySQL over HTTP) records for ruby and rails projects}
|
21
|
+
gem.email = "rlister@github"
|
22
|
+
gem.authors = ["Richard Lister"]
|
23
|
+
end
|
24
|
+
Jeweler::RubygemsDotOrgTasks.new
|
25
|
+
|
26
|
+
require 'rake/testtask'
|
27
|
+
Rake::TestTask.new(:test) do |test|
|
28
|
+
test.libs << 'lib' << 'test'
|
29
|
+
test.pattern = 'test/**/test_*.rb'
|
30
|
+
test.verbose = true
|
31
|
+
end
|
32
|
+
|
33
|
+
require 'rcov/rcovtask'
|
34
|
+
Rcov::RcovTask.new do |test|
|
35
|
+
test.libs << 'test'
|
36
|
+
test.pattern = 'test/**/test_*.rb'
|
37
|
+
test.verbose = true
|
38
|
+
test.rcov_opts << '--exclude "gems/*"'
|
39
|
+
end
|
40
|
+
|
41
|
+
task :default => :test
|
42
|
+
|
43
|
+
require 'rake/rdoctask'
|
44
|
+
Rake::RDocTask.new do |rdoc|
|
45
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
46
|
+
|
47
|
+
rdoc.rdoc_dir = 'rdoc'
|
48
|
+
rdoc.title = "atomics_resource #{version}"
|
49
|
+
rdoc.rdoc_files.include('README*')
|
50
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
51
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
## this does not run, but will show you how to configure against your local Atomics instance
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'atomics_resource'
|
7
|
+
|
8
|
+
ATOMICS_CONFIG = {
|
9
|
+
'hr' => {
|
10
|
+
'host' => 'hr-atomics.newco.com',
|
11
|
+
'port' => '8080',
|
12
|
+
'path' => '/jAtomics/select/?version=1',
|
13
|
+
},
|
14
|
+
'other' => {
|
15
|
+
'host' => 'other-atomics.for.illustration.com',
|
16
|
+
'port' => '80',
|
17
|
+
'path' => '/atomics/raw',
|
18
|
+
},
|
19
|
+
}
|
20
|
+
|
21
|
+
class Employee < AtomicsResource::Base
|
22
|
+
set_atomics_type :hr
|
23
|
+
set_table_name :employee_display
|
24
|
+
set_primary_key :id
|
25
|
+
|
26
|
+
column :first_name
|
27
|
+
column :last_name
|
28
|
+
column :title
|
29
|
+
column :team_id
|
30
|
+
end
|
31
|
+
|
32
|
+
employees = Employee.all(:conditions => {:team_id => 1},
|
33
|
+
:order => [:last_name, :first_name])
|
34
|
+
|
35
|
+
employees.each do |e|
|
36
|
+
puts "#{e.last_name},#{e.first_name}: #{e.title}"
|
37
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2011 Richard Lister
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
## ActiveModel-style interface for Atomics queries.
|
25
|
+
|
26
|
+
require 'atomics_resource/base.rb'
|
27
|
+
|
28
|
+
module AtomicsResource
|
29
|
+
## noop
|
30
|
+
end
|
@@ -0,0 +1,246 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'net/http'
|
4
|
+
|
5
|
+
module AtomicsResource
|
6
|
+
|
7
|
+
class Base
|
8
|
+
|
9
|
+
## class instance variables
|
10
|
+
class << self
|
11
|
+
attr_accessor :atomics_type, :table_name, :primary_key
|
12
|
+
alias_method :set_atomics_type, :atomics_type=
|
13
|
+
alias_method :set_table_name, :table_name=
|
14
|
+
alias_method :set_primary_key, :primary_key=
|
15
|
+
end
|
16
|
+
|
17
|
+
## Get method for array of columns (attr_accessor will break for arrays on inheritance).
|
18
|
+
def self.columns
|
19
|
+
@columns ||= []
|
20
|
+
end
|
21
|
+
|
22
|
+
## Add a column.
|
23
|
+
def self.column(value)
|
24
|
+
columns << value
|
25
|
+
end
|
26
|
+
|
27
|
+
## Quote value for Atomics in SQL statment; numeric arguments returned unquoted,
|
28
|
+
## strings in single quotes.
|
29
|
+
def self.quote_value(value)
|
30
|
+
value.match(/^\d+$/) ? value : "'#{value}'"
|
31
|
+
end
|
32
|
+
|
33
|
+
## Build a SQL query string from hash of options passed to find.
|
34
|
+
def self.construct_sql(options)
|
35
|
+
sql = []
|
36
|
+
sql << "SELECT " + construct_sql_for_params(options[:select])
|
37
|
+
sql << "FROM " + construct_sql_for_params(options[:from])
|
38
|
+
sql << "WHERE " + construct_sql_for_conditions(options[:conditions]) if options[:conditions]
|
39
|
+
sql << "ORDER BY " + construct_sql_for_params(options[:order]) if options[:order]
|
40
|
+
sql << "LIMIT " + options[:limit].to_s if options[:limit]
|
41
|
+
sql << "OFFSET " + options[:offset].to_s if options[:offset]
|
42
|
+
sql.join(' ')
|
43
|
+
end
|
44
|
+
|
45
|
+
## Return string for SQL conditions from values params as string, array, or hash.
|
46
|
+
def self.construct_sql_for_params(parms)
|
47
|
+
case parms
|
48
|
+
when Array; parms.map(&:to_s).join(',')
|
49
|
+
when Hash; parms.keys.map(&:to_s).join(',')
|
50
|
+
else parms.to_s
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
## Return string for SQL conditions from options params as string, array, or hash.
|
55
|
+
def self.construct_sql_for_conditions(option)
|
56
|
+
case option
|
57
|
+
when Array; construct_sql_for_array(option)
|
58
|
+
when Hash; construct_sql_for_hash (option) ## :TODO: implement this
|
59
|
+
else option
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
## Construct string of conditions from an array of format plus values to substitute.
|
64
|
+
## Examples:
|
65
|
+
## [ 'foo = ? AND bar = ?', 'hello', 99 ]
|
66
|
+
## [ 'foo = %s AND bar = %d", 'hello', 99 ]
|
67
|
+
def self.construct_sql_for_array(a)
|
68
|
+
format, *values = a
|
69
|
+
if format.include?("\?")
|
70
|
+
raise ArgumentError unless format.count('\?') == values.size # sanity check right number args
|
71
|
+
format.gsub(/\?/) { quote_value(values.shift.to_s) } # replace all ? with args
|
72
|
+
elsif format.blank?
|
73
|
+
format
|
74
|
+
else # replace sprintf escapes
|
75
|
+
format % values.collect { |value| quote_value(value.to_s) }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
## Construct string of conditions from a hash of format plus values to substitute.
|
80
|
+
## Allows conditions as hash of key/value pairs to be ANDed together.
|
81
|
+
## Examples:
|
82
|
+
## { :foo => :hello, :bar => 99 }
|
83
|
+
def self.construct_sql_for_hash(h)
|
84
|
+
h.map{|k,v| "#{k}=#{quote_value(v.to_s)}"}.join(' AND ')
|
85
|
+
end
|
86
|
+
|
87
|
+
## Calls find and returns array of all matches.
|
88
|
+
def self.all(*args)
|
89
|
+
find(:all, *args)
|
90
|
+
end
|
91
|
+
|
92
|
+
## Calls find and returns first matching object.
|
93
|
+
def self.first(*args)
|
94
|
+
find(:first, *args)
|
95
|
+
end
|
96
|
+
|
97
|
+
## Calls find and returns last matching object.
|
98
|
+
def self.last(*args)
|
99
|
+
find(:last, *args)
|
100
|
+
end
|
101
|
+
|
102
|
+
## Find takes a list of conditions as a hash, and returns array of matching objects.
|
103
|
+
## If single argument is numeric, return first object to match by primary key.
|
104
|
+
def self.find(*arguments)
|
105
|
+
scope = arguments.slice!(0)
|
106
|
+
options = arguments.slice!(0) || {}
|
107
|
+
|
108
|
+
case scope
|
109
|
+
when :all then find_every(options) # Employee.find(:all, :conditions => 'team_id = 156')
|
110
|
+
when :first then find_every(options).first # Employee.find(:first, :conditions => 'team_id = 156')
|
111
|
+
when :last then find_every(options).last # Employee.find(:last, :conditions => 'team_id = 156')
|
112
|
+
else find_single(scope, options) # Employee.find(7923113)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
## Return array of columns to use for SELECT statements, ensuring we get primary_key, or single
|
117
|
+
## string '*' if no columns set.
|
118
|
+
def self.columns_or_default
|
119
|
+
columns.empty? ? '*' : ([primary_key]+columns).uniq
|
120
|
+
end
|
121
|
+
|
122
|
+
## Find array of all matching records.
|
123
|
+
def self.find_every(options)
|
124
|
+
defaults = { :select => columns_or_default, :from => table_name }
|
125
|
+
sql = construct_sql(defaults.merge(options))
|
126
|
+
find_by_sql(sql)
|
127
|
+
end
|
128
|
+
|
129
|
+
## Find a single record with given primary key.
|
130
|
+
def self.find_single(scope, options)
|
131
|
+
defaults = { :select => columns_or_default, :from => table_name, :conditions => {primary_key => scope} }
|
132
|
+
sql = construct_sql(defaults)
|
133
|
+
find_by_sql(sql).first
|
134
|
+
end
|
135
|
+
|
136
|
+
## Return string with whole URL for request, adding given SQL string as query.
|
137
|
+
def self.construct_url_for_sql(sql)
|
138
|
+
(host, port, path) = ATOMICS_CONFIG[atomics_type.to_s].values_at('host', 'port', 'path')
|
139
|
+
"http://#{host}:#{port}#{path}&q=#{URI.escape(sql)}"
|
140
|
+
end
|
141
|
+
|
142
|
+
## Find matches using raw SQL statement given as a string.
|
143
|
+
## args:: string containing SQL statement.
|
144
|
+
## returns:: array of objects.
|
145
|
+
def self.find_by_sql(sql)
|
146
|
+
url = construct_url_for_sql(sql)
|
147
|
+
|
148
|
+
## get the xml doc as a nokogiri object
|
149
|
+
doc = Nokogiri::XML(open(url))
|
150
|
+
|
151
|
+
|
152
|
+
## array of records
|
153
|
+
records = doc.xpath('//record').to_a.map do |record|
|
154
|
+
|
155
|
+
## convert record into a hash with name => value
|
156
|
+
hash = record.xpath('./field').inject({}) do |hash, field|
|
157
|
+
hash[field.xpath('./name')[0].content] = field.xpath('./value')[0].content
|
158
|
+
hash
|
159
|
+
end
|
160
|
+
|
161
|
+
## instantiate record object
|
162
|
+
new(hash)
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
## What uses this?
|
168
|
+
def self.to_model
|
169
|
+
self
|
170
|
+
end
|
171
|
+
|
172
|
+
## instance variables
|
173
|
+
attr_accessor :attributes
|
174
|
+
|
175
|
+
## Constructor allows hash as arg to set attributes.
|
176
|
+
def initialize(attributes = {})
|
177
|
+
hsh = {}
|
178
|
+
@attributes = hsh.respond_to?(:with_indifferent_access) ? hsh.with_indifferent_access : hsh
|
179
|
+
load(attributes)
|
180
|
+
end
|
181
|
+
|
182
|
+
## Set attributes for an existing instance of this object.
|
183
|
+
def load(attributes)
|
184
|
+
raise ArgumentError, "expected an attributes Hash, got #{attributes.inspect}" unless attributes.is_a?(Hash)
|
185
|
+
attributes.each do |key, value|
|
186
|
+
@attributes[key.to_s] = value.dup rescue value
|
187
|
+
end
|
188
|
+
self
|
189
|
+
end
|
190
|
+
|
191
|
+
## Return formatted inspection string for record with attributes listed.
|
192
|
+
def inspect
|
193
|
+
attributes_string = @attributes.map{|k,v| "#{k}: #{value_for_inspect(v)}"}.join(', ')
|
194
|
+
"#<#{self.class} #{attributes_string}>"
|
195
|
+
end
|
196
|
+
|
197
|
+
## Returns inspect for a value, with strings shortened to 50 chars, for use in Object.inspect.
|
198
|
+
def value_for_inspect(value)
|
199
|
+
if value.is_a?(String) && value.length > 50
|
200
|
+
"#{value[0..50]}...".inspect
|
201
|
+
else
|
202
|
+
value.inspect
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
## Get attributes as methods, like active_model.
|
207
|
+
def method_missing(method_symbol, *arguments)
|
208
|
+
method_name = method_symbol.to_s
|
209
|
+
if method_name =~ /=$/
|
210
|
+
attributes[$`] = arguments.first
|
211
|
+
elsif method_name =~ /\?$/
|
212
|
+
attributes[$`]
|
213
|
+
else
|
214
|
+
return attributes[method_name] if attributes.include?(method_name)
|
215
|
+
super
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
## Get attributes using hash syntax.
|
220
|
+
def [](attr)
|
221
|
+
attributes[attr]
|
222
|
+
end
|
223
|
+
|
224
|
+
## Value of primary key.
|
225
|
+
def id
|
226
|
+
attributes[self.class.primary_key].to_i
|
227
|
+
end
|
228
|
+
|
229
|
+
## What uses this?
|
230
|
+
def to_key
|
231
|
+
[id]
|
232
|
+
end
|
233
|
+
|
234
|
+
## Return primary_key as param for object, for polymorphic route generation to work from object in view.
|
235
|
+
def to_param
|
236
|
+
attributes[self.class.primary_key]
|
237
|
+
end
|
238
|
+
|
239
|
+
end
|
240
|
+
|
241
|
+
## Do some mix-ins to get various bits of rails coolness, skip these for non-rails.
|
242
|
+
if defined? RAILS_ROOT
|
243
|
+
extend ActiveModel::Naming # need this for model_name and variants, used to get paths from objects
|
244
|
+
end
|
245
|
+
|
246
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper.rb'
|
2
|
+
|
3
|
+
# ATOMICS_CONFIG = YAML.load_file("atomics.yml")
|
4
|
+
|
5
|
+
ATOMICS_CONFIG = {
|
6
|
+
'my_type' => {
|
7
|
+
'host' => 'orb-atomics.ops.aol.com',
|
8
|
+
'port' => '8080',
|
9
|
+
'path' => '/jAtomics/select/?version=1'
|
10
|
+
}
|
11
|
+
}
|
12
|
+
|
13
|
+
module AtomicsResource
|
14
|
+
describe Base do
|
15
|
+
before :each do
|
16
|
+
class MyTest < AtomicsResource::Base
|
17
|
+
set_atomics_type :my_type
|
18
|
+
set_table_name :my_table
|
19
|
+
set_primary_key :my_pk
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "class variables" do
|
24
|
+
it "should have class settings" do
|
25
|
+
MyTest.atomics_type.should == :my_type
|
26
|
+
MyTest.table_name.should == :my_table
|
27
|
+
MyTest.primary_key.should == :my_pk
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "atomics config" do
|
32
|
+
require 'uri'
|
33
|
+
it "should create a valid base URL" do
|
34
|
+
sql = "select * from foo where bar = 'wibble'"
|
35
|
+
URI.parse(MyTest.construct_url_for_sql(sql)).class.should == URI::HTTP
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "sql construction" do
|
40
|
+
it "should construct sql from array conditions" do
|
41
|
+
a = MyTest.construct_sql_for_conditions(["foo = \? AND bar = \?", :hello, :world])
|
42
|
+
a.should == "foo = 'hello' AND bar = 'world'"
|
43
|
+
end
|
44
|
+
it "should contruct sql from hash conditions" do
|
45
|
+
b = MyTest.construct_sql_for_conditions({:foo => :hello, :bar => :world})
|
46
|
+
b.should == "foo='hello' AND bar='world'"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
metadata
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: atomics_resource
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Richard Lister
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-08-15 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: nokogiri
|
17
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: "0"
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *id001
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: shoulda
|
28
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *id002
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: bundler
|
39
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: 1.0.0
|
45
|
+
type: :development
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *id003
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: jeweler
|
50
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ~>
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 1.6.4
|
56
|
+
type: :development
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: *id004
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: rcov
|
61
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: "0"
|
67
|
+
type: :development
|
68
|
+
prerelease: false
|
69
|
+
version_requirements: *id005
|
70
|
+
description: Model Atomics (MySQL over HTTP) records for ruby and rails projects
|
71
|
+
email: rlister@github
|
72
|
+
executables: []
|
73
|
+
|
74
|
+
extensions: []
|
75
|
+
|
76
|
+
extra_rdoc_files:
|
77
|
+
- LICENSE.txt
|
78
|
+
- README.rdoc
|
79
|
+
files:
|
80
|
+
- .document
|
81
|
+
- Gemfile
|
82
|
+
- Gemfile.lock
|
83
|
+
- LICENSE.txt
|
84
|
+
- README.rdoc
|
85
|
+
- Rakefile
|
86
|
+
- VERSION
|
87
|
+
- examples/employees.rb
|
88
|
+
- lib/atomics_resource.rb
|
89
|
+
- lib/atomics_resource/base.rb
|
90
|
+
- test/helper.rb
|
91
|
+
- test/spec_atomics_resource.rb
|
92
|
+
- test/test_atomics_resource.rb
|
93
|
+
homepage: http://github.com/rlister/atomics_resource
|
94
|
+
licenses:
|
95
|
+
- MIT
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
|
99
|
+
require_paths:
|
100
|
+
- lib
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
none: false
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
hash: 1985330703577403544
|
107
|
+
segments:
|
108
|
+
- 0
|
109
|
+
version: "0"
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: "0"
|
116
|
+
requirements: []
|
117
|
+
|
118
|
+
rubyforge_project:
|
119
|
+
rubygems_version: 1.8.5
|
120
|
+
signing_key:
|
121
|
+
specification_version: 3
|
122
|
+
summary: Active Model for Atomics MySQL lookups
|
123
|
+
test_files: []
|
124
|
+
|