yarel 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/lib/yarel.rb +26 -0
- data/lib/yarel/base.rb +36 -0
- data/lib/yarel/connection.rb +10 -0
- data/lib/yarel/extensions/object_extensions.rb +7 -0
- data/lib/yarel/table.rb +82 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/yarel/base_spec.rb +36 -0
- data/spec/yarel/yarel_spec.rb +91 -0
- metadata +114 -0
data/lib/yarel.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'active_model'
|
3
|
+
require 'net/http'
|
4
|
+
require 'cgi'
|
5
|
+
require 'active_support/core_ext/object/try'
|
6
|
+
require 'active_support/core_ext/string/inflections'
|
7
|
+
require 'active_support/core_ext/module/attribute_accessors'
|
8
|
+
require 'active_support/core_ext/module/delegation'
|
9
|
+
require 'active_support/core_ext/class/attribute_accessors'
|
10
|
+
|
11
|
+
module Yarel
|
12
|
+
extend ActiveSupport::Autoload
|
13
|
+
eager_autoload do
|
14
|
+
autoload :Table
|
15
|
+
autoload :Connection
|
16
|
+
# autoload :Base
|
17
|
+
end
|
18
|
+
|
19
|
+
def Yarel.const_missing(const_name)
|
20
|
+
yql_table_name = const_name.to_s.underscore.gsub("_", ".")
|
21
|
+
const_set const_name, Table.new(yql_table_name)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
require 'yarel/extensions/object_extensions'
|
25
|
+
|
26
|
+
Logger = ActiveSupport::BufferedLogger.new(File.open('yarel.log', 'w+')) unless Module.const_defined?("Logger")
|
data/lib/yarel/base.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module Yarel
|
2
|
+
class Exception < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
module Base
|
6
|
+
attr_accessor :count
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def all
|
10
|
+
response = Connection.get(table.to_yql)
|
11
|
+
raise Exception.new(response["error"]["description"]) if response["error"]
|
12
|
+
[response["query"]["results"].first[1]].flatten
|
13
|
+
end
|
14
|
+
|
15
|
+
[:sort, :order, :limit, :where, :from, :project, :select].each do |chainable_method|
|
16
|
+
class_eval <<-RUBY_EVAL, __FILE__, __LINE__
|
17
|
+
def #{chainable_method}(*args)
|
18
|
+
self.table = self.table.send(:#{chainable_method}, *args)
|
19
|
+
self
|
20
|
+
end
|
21
|
+
RUBY_EVAL
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.included(klass)
|
26
|
+
klass.cattr_accessor :table
|
27
|
+
klass.table = Table.new(klass.name.underscore.gsub("/", "."), klass)
|
28
|
+
klass.instance_eval do
|
29
|
+
class << self
|
30
|
+
delegate :to_yql, :to => :table
|
31
|
+
end
|
32
|
+
end
|
33
|
+
klass.extend ClassMethods
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Yarel
|
2
|
+
class Connection
|
3
|
+
END_POINT_URL = 'http://query.yahooapis.com/v1/public/yql'
|
4
|
+
|
5
|
+
def self.get(yql)
|
6
|
+
response = Net::HTTP.post_form(URI.parse(END_POINT_URL), { :q => yql, :format => :json })
|
7
|
+
ActiveSupport::JSON.decode response.body
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
data/lib/yarel/table.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
module Yarel
|
2
|
+
class Exception < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
class Table
|
6
|
+
attr_accessor :table_name, :projections, :conditions, :limit_to, :offset, :sort_columns
|
7
|
+
|
8
|
+
def initialize(table_name)
|
9
|
+
@table_name = table_name
|
10
|
+
@projections = "*"
|
11
|
+
@conditions = []
|
12
|
+
@limit_to = @offset = :default
|
13
|
+
end
|
14
|
+
|
15
|
+
def all
|
16
|
+
yql = to_yql
|
17
|
+
Logger.info "Generated YQL: #{yql.inspect}\n"
|
18
|
+
response = Connection.get(yql)
|
19
|
+
raise Exception.new(response["error"]["description"]) if response["error"]
|
20
|
+
response["query"]["results"] ? [response["query"]["results"].first[1]].flatten : []
|
21
|
+
end
|
22
|
+
|
23
|
+
def from(table_name)
|
24
|
+
modify_clone { self.table_name = table_name }
|
25
|
+
end
|
26
|
+
|
27
|
+
def project(*field_names)
|
28
|
+
modify_clone { self.projections = field_names.join(", ") }
|
29
|
+
end
|
30
|
+
|
31
|
+
alias_method :select, :project
|
32
|
+
|
33
|
+
def where(condition)
|
34
|
+
new_condition =
|
35
|
+
case
|
36
|
+
when condition.kind_of?(Hash)
|
37
|
+
condition.map do |key, value|
|
38
|
+
condition_string = value.kind_of?(self.class) ? "#{key} in ( #{value.to_yql} )" : "#{key} = '#{value}'"
|
39
|
+
end
|
40
|
+
when condition.kind_of?(String)
|
41
|
+
condition
|
42
|
+
when condition.kind_of?(Array)
|
43
|
+
send :sprintf, condition[0].gsub("?", "'%s'"), *condition[1..-1]
|
44
|
+
end
|
45
|
+
|
46
|
+
modify_clone { self.conditions << new_condition }
|
47
|
+
end
|
48
|
+
|
49
|
+
def limit(*options)
|
50
|
+
lim = options[0]
|
51
|
+
off, lim = options[0..1] unless options.size == 1
|
52
|
+
modify_clone {
|
53
|
+
self.limit_to = lim.to_i if lim
|
54
|
+
self.offset = off.to_i if off
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
def sort(*columns)
|
59
|
+
modify_clone { self.sort_columns = columns.try(:join, ", ") }
|
60
|
+
end
|
61
|
+
|
62
|
+
alias_method :order, :sort
|
63
|
+
|
64
|
+
def to_yql
|
65
|
+
yql = ["SELECT #{projections} FROM #{table_name}"]
|
66
|
+
yql << "WHERE #{conditions.join(' AND ')}" unless conditions.empty?
|
67
|
+
yql << "LIMIT #{limit_to}" if limit_to != :default
|
68
|
+
yql << "OFFSET #{offset}" if offset != :default
|
69
|
+
yql << "| sort(field='#{sort_columns}')" if sort_columns
|
70
|
+
yql.join " "
|
71
|
+
end
|
72
|
+
|
73
|
+
alias_method :to_s, :to_yql
|
74
|
+
|
75
|
+
private
|
76
|
+
def modify_clone(&block)
|
77
|
+
cloned_obj = self.deep_clone
|
78
|
+
cloned_obj.instance_eval &block
|
79
|
+
cloned_obj
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Yarel::Base" do
|
4
|
+
LocalSearch = Yarel::Table.new("local.search")
|
5
|
+
|
6
|
+
it "should create an instance of table" do
|
7
|
+
LocalSearch.should be_kind_of Yarel::Table
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "all" do
|
11
|
+
it "should raise exception back if response has errors" do
|
12
|
+
lambda {
|
13
|
+
LocalSearch.order('test').all
|
14
|
+
}.should raise_error(Yarel::Exception, "Cannot find required keys in where clause; expecting required keys: (query, longitude, latitude)")
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should take the result part alone" do
|
18
|
+
GeoPlaces = Yarel::Table.new("geo.places")
|
19
|
+
GeoPlaces.where(:text => "north beach, san francisco").all.should == [{"name"=>"North Beach", "woeid"=>"2460640", "uri"=>"http://where.yahooapis.com/v1/place/2460640", "boundingBox"=>{"northEast"=>{"latitude"=>"37.808270", "longitude"=>"-122.399467"}, "southWest"=>{"latitude"=>"37.795399", "longitude"=>"-122.418381"}}, "postal"=>{"type"=>"Zip Code", "content"=>"94133"}, "country"=>{"code"=>"US", "type"=>"Country", "content"=>"United States"}, "placeTypeName"=>{"code"=>"22", "content"=>"Suburb"}, "centroid"=>{"latitude"=>"37.805939", "longitude"=>"-122.411118"}, "areaRank"=>"1", "admin1"=>{"code"=>"US-CA", "type"=>"State", "content"=>"California"}, "popRank"=>"0", "locality1"=>{"type"=>"Town", "content"=>"San Francisco"}, "admin2"=>{"code"=>"", "type"=>"County", "content"=>"San Francisco"}, "lang"=>"en-US", "locality2"=>{"type"=>"Suburb", "content"=>"North Beach"}, "admin3"=>nil}]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should return mulitple records" do
|
23
|
+
LocalNewSearch = Yarel::Table.new("local.search")
|
24
|
+
|
25
|
+
LocalNewSearch.where(:zip => 94085, :query => 'pizza').limit(2).all.should == [
|
26
|
+
{"MapUrl"=>"http://maps.yahoo.com/maps_result?q1=1127+N+Lawrence+Expy+Sunnyvale+CA&gid1=21341983", "Distance"=>"1.28", "Longitude"=>"-121.996017", "City"=>"Sunnyvale", "Url"=>"http://local.yahoo.com/info-21341983-giovannis-pizzeria-sunnyvale", "Title"=>"Giovannis Pizzeria", "Latitude"=>"37.397058", "Phone"=>"(408) 734-4221", "id"=>"21341983", "Categories"=>{"Category"=>[{"id"=>"96926234", "content"=>"Carry Out & Take Out"}, {"id"=>"96926236", "content"=>"Restaurants"}, {"id"=>"96926243", "content"=>"Pizza"}]}, "BusinessUrl"=>"http://giovannisnypizza.com/", "ClickUrl"=>"http://local.yahoo.com/info-21341983-giovannis-pizzeria-sunnyvale", "Rating"=>{"TotalReviews"=>"44", "AverageRating"=>"4", "TotalRatings"=>"44", "LastReviewIntro"=>"this is one of the best pizzas i had..very tasty,crispy..value for the money spent..try it out once", "LastReviewDate"=>"1273837240"}, "Address"=>"1127 N Lawrence Expy", "State"=>"CA", "BusinessClickUrl"=>"http://giovannisnypizza.com/"},
|
27
|
+
{"MapUrl"=>"http://maps.yahoo.com/maps_result?q1=1155+Reed+Ave+Sunnyvale+CA&gid1=21332026", "Distance"=>"1.79", "Longitude"=>"-121.997904", "City"=>"Sunnyvale", "Url"=>"http://local.yahoo.com/info-21332026-vitos-famous-pizza-sunnyvale", "Title"=>"Vitos Famous Pizza", "Latitude"=>"37.367029", "Phone"=>"(408) 246-8800", "id"=>"21332026", "Categories"=>{"Category"=>[{"id"=>"96926190", "content"=>"Italian Restaurants"}, {"id"=>"96926234", "content"=>"Carry Out & Take Out"}, {"id"=>"96926236", "content"=>"Restaurants"}, {"id"=>"96926242", "content"=>"Fast Food"}, {"id"=>"96926243", "content"=>"Pizza"}]}, "BusinessUrl"=>"http://vitosfamouspizza.com/", "ClickUrl"=>"http://local.yahoo.com/info-21332026-vitos-famous-pizza-sunnyvale", "Rating"=>{"TotalReviews"=>"16", "AverageRating"=>"4.5", "TotalRatings"=>"16", "LastReviewIntro"=>"As an East Coaster, I am picky about my pizza, and this place is really a great find!", "LastReviewDate"=>"1247669752"}, "Address"=>"1155 Reed Ave", "State"=>"CA", "BusinessClickUrl"=>"http://vitosfamouspizza.com/"}
|
28
|
+
]
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should handle empty results" do
|
32
|
+
places = Yarel::Table.new("geo.places")
|
33
|
+
places.where(:text => "unkown place").all.should == []
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "yarel" do
|
4
|
+
before(:each) do
|
5
|
+
@table_name = "answers.getbycategory"
|
6
|
+
@yarel_table = Yarel::Table.new(@table_name)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should be chainable" do
|
10
|
+
@yarel_table.from("answers.new_table").should be_kind_of(Yarel::Table)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "return the yql" do
|
14
|
+
it "should be constructed taking the table name" do
|
15
|
+
yarel_table = Yarel::Table.new("ns.table_name").to_yql.should == "SELECT * FROM ns.table_name"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "for from" do
|
19
|
+
@yarel_table.from("answers.new_table").to_yql.should == "SELECT * FROM answers.new_table"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "for the latest from" do
|
23
|
+
@yarel_table.from("answers.new_table").from("answers.new_new_table").to_yql.should == "SELECT * FROM answers.new_new_table"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "for project" do
|
27
|
+
@yarel_table.project(:this_column).to_yql.should == "SELECT this_column FROM answers.getbycategory"
|
28
|
+
@yarel_table.project(:this_column, :that_column).to_yql.should == "SELECT this_column, that_column FROM answers.getbycategory"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "for limit" do
|
32
|
+
@yarel_table.limit(10).to_yql.should == "SELECT * FROM answers.getbycategory LIMIT 10"
|
33
|
+
end
|
34
|
+
|
35
|
+
it "for limit should not mutate" do
|
36
|
+
q1 = @yarel_table.limit(10)
|
37
|
+
q2 = @yarel_table.limit(5)
|
38
|
+
q1.to_yql.should == "SELECT * FROM answers.getbycategory LIMIT 10"
|
39
|
+
q2.to_yql.should == "SELECT * FROM answers.getbycategory LIMIT 5"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "for offset along with limit" do
|
43
|
+
@yarel_table.limit(10, 20).to_yql.should == "SELECT * FROM answers.getbycategory LIMIT 20 OFFSET 10"
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "where" do
|
47
|
+
it "hash" do
|
48
|
+
@yarel_table.where(:this_column => 5).to_yql.should == "SELECT * FROM answers.getbycategory WHERE this_column = '5'"
|
49
|
+
end
|
50
|
+
|
51
|
+
it "string" do
|
52
|
+
@yarel_table.where("this_column = '5'").to_yql.should == "SELECT * FROM answers.getbycategory WHERE this_column = '5'"
|
53
|
+
end
|
54
|
+
|
55
|
+
it "array interpolation" do
|
56
|
+
@yarel_table.where(["this_column = ?", 'asd']).to_yql.should == "SELECT * FROM answers.getbycategory WHERE this_column = 'asd'"
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should multiple interpolation" do
|
60
|
+
@yarel_table.where(["this_column = ? AND that_column = ?", 5, 10]).to_yql.should == "SELECT * FROM answers.getbycategory WHERE this_column = '5' AND that_column = '10'"
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should be able to call multiple times" do
|
64
|
+
@yarel_table.where(["this_column = ?", 5]).project(:this_column).where(:that_column => 10).to_yql.should == "SELECT this_column FROM answers.getbycategory WHERE this_column = '5' AND that_column = '10'"
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should not mutate the current object" do
|
68
|
+
@yarel_table.where(["this_column = ?", 5]).to_yql.should == "SELECT * FROM answers.getbycategory WHERE this_column = '5'"
|
69
|
+
@yarel_table.where(["this_column = ? AND that_column = ?", 5, 10]).to_yql.should == "SELECT * FROM answers.getbycategory WHERE this_column = '5' AND that_column = '10'"
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "where with sub queries" do
|
73
|
+
it "as a hash" do
|
74
|
+
@yarel_table.where(:this_column => Yarel::Table.new(:sub_table).project("sub_table_column")).to_yql.should ==
|
75
|
+
"SELECT * FROM answers.getbycategory WHERE this_column in ( SELECT sub_table_column FROM sub_table )"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
it "for sort" do
|
81
|
+
@yarel_table.sort('Rating.AverageRating').to_s.should == "SELECT * FROM answers.getbycategory | sort(field='Rating.AverageRating')"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
describe "yarel module" do
|
88
|
+
it "should construct table object" do
|
89
|
+
Yarel::GeoLocation.should be_kind_of Yarel::Table
|
90
|
+
end
|
91
|
+
end
|
metadata
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: yarel
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Selvakumar Natesan
|
13
|
+
- Sharanya Sennimalai
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-07-25 00:00:00 +05:30
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: activesupport
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 3
|
30
|
+
- 0
|
31
|
+
- 0
|
32
|
+
- beta4
|
33
|
+
version: 3.0.0.beta4
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: activemodel
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
segments:
|
44
|
+
- 3
|
45
|
+
- 0
|
46
|
+
- 0
|
47
|
+
- beta4
|
48
|
+
version: 3.0.0.beta4
|
49
|
+
type: :runtime
|
50
|
+
version_requirements: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
name: rspec
|
53
|
+
prerelease: false
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
type: :development
|
62
|
+
version_requirements: *id003
|
63
|
+
description: Object-relational mapper for Yahoo Query Language - A Object Relation Mapper for YQL in ruby, very similar to ActiveRecord 3.0.0 with chainability and lazy evaluation of queries
|
64
|
+
email:
|
65
|
+
- k.n.selvakumar@gmail.com
|
66
|
+
- s.sharanya@gmail.com
|
67
|
+
executables: []
|
68
|
+
|
69
|
+
extensions: []
|
70
|
+
|
71
|
+
extra_rdoc_files: []
|
72
|
+
|
73
|
+
files:
|
74
|
+
- lib/yarel/base.rb
|
75
|
+
- lib/yarel/connection.rb
|
76
|
+
- lib/yarel/extensions/object_extensions.rb
|
77
|
+
- lib/yarel/table.rb
|
78
|
+
- lib/yarel.rb
|
79
|
+
has_rdoc: true
|
80
|
+
homepage: http://github.com/selvakn/yarel
|
81
|
+
licenses: []
|
82
|
+
|
83
|
+
post_install_message:
|
84
|
+
rdoc_options: []
|
85
|
+
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
segments:
|
93
|
+
- 1
|
94
|
+
- 8
|
95
|
+
- 7
|
96
|
+
version: 1.8.7
|
97
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
segments:
|
102
|
+
- 0
|
103
|
+
version: "0"
|
104
|
+
requirements: []
|
105
|
+
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 1.3.6
|
108
|
+
signing_key:
|
109
|
+
specification_version: 3
|
110
|
+
summary: Object-relational mapper for Yahoo Query Language
|
111
|
+
test_files:
|
112
|
+
- spec/spec_helper.rb
|
113
|
+
- spec/yarel/base_spec.rb
|
114
|
+
- spec/yarel/yarel_spec.rb
|