yarel 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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")
@@ -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
@@ -0,0 +1,7 @@
1
+ module ObjectExtensions
2
+ def deep_clone
3
+ Marshal.load( Marshal.dump(self))
4
+ end
5
+ end
6
+
7
+ Object.send :include, ObjectExtensions
@@ -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
@@ -0,0 +1,5 @@
1
+ $LOAD_PATH.unshift File.join File.dirname(__FILE__) + "/../lib"
2
+
3
+ require 'rubygems'
4
+ require 'spec'
5
+ require 'yarel'
@@ -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