perry 0.4.0

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.
@@ -0,0 +1,56 @@
1
+ module Perry::FinderMethods
2
+
3
+ def find(ids_or_mode, options={})
4
+ case ids_or_mode
5
+ when Fixnum, String
6
+ self.where(:id => ids_or_mode.to_i).first(options) || raise(Perry::RecordNotFound, "Could not find #{@klass} with :id = #{ids_or_mode}")
7
+ when Array
8
+ self.where(:id => ids_or_mode).all(options).tap do |result|
9
+ raise Perry::RecordNotFound, "Couldn't find all #{@klass} with ids (#{ids_or_mode.join(',')}) (expected #{ids_or_mode.size} records but got #{result.size})." unless result.size == ids_or_mode.size
10
+ end
11
+ when :all
12
+ self.all(options)
13
+ when :first
14
+ self.first(options)
15
+ else
16
+ raise ArgumentError, "Unknown arguments for method find"
17
+ end
18
+ end
19
+
20
+ def all(options={})
21
+ self.apply_finder_options(options).to_a
22
+ end
23
+
24
+ def first(options={})
25
+ self.apply_finder_options(options).limit(1).to_a.first
26
+ end
27
+
28
+ def search(options={})
29
+ relation = self
30
+ options.each do |search, *args|
31
+ relation = relation.send(search, *args) if @klass.send(:condition_details, search)
32
+ end
33
+ relation
34
+ end
35
+
36
+ def apply_finder_options(options)
37
+ relation = clone
38
+ return relation unless options
39
+
40
+ [:joins, :limit, :offset, :order, :select, :group, :having, :from, :fresh, :includes].each do |finder|
41
+ relation = relation.send(finder, options[finder]) if options[finder]
42
+ end
43
+
44
+ relation = relation.where(options[:conditions]) if options.has_key?(:conditions)
45
+ relation = relation.where(options[:where]) if options.has_key?(:where)
46
+
47
+ relation = relation.includes(options[:include]) if options.has_key?(:include)
48
+
49
+ relation = relation.search(options[:search]) if options.has_key?(:search)
50
+
51
+ relation = relation.sql(options[:sql]) if options.has_key?(:sql)
52
+
53
+ relation
54
+ end
55
+
56
+ end
@@ -0,0 +1,69 @@
1
+ module Perry::QueryMethods
2
+ # TRP: Define each of the variables the query options will be stored in.
3
+ attr_accessor :select_values, :group_values, :order_values, :joins_values, :includes_values, :where_values, :having_values,
4
+ :limit_value, :offset_value, :from_value,
5
+ :raw_sql_value, :fresh_value
6
+
7
+ def select(*args)
8
+ if block_given?
9
+ to_a.select {|*block_args| yield(*block_args) }
10
+ else
11
+ clone.tap { |r| r.select_values += args if args_valid? args }
12
+ end
13
+ end
14
+
15
+ def group(*args)
16
+ clone.tap { |r| r.group_values += args if args_valid? args }
17
+ end
18
+
19
+ def order(*args)
20
+ clone.tap { |r| r.order_values += args if args_valid? args }
21
+ end
22
+
23
+ def joins(*args)
24
+ clone.tap { |r| r.joins_values += args if args_valid?(args) }
25
+ end
26
+
27
+ def includes(*args)
28
+ args.reject! { |a| a.nil? }
29
+ clone.tap { |r| r.includes_values += (r.includes_values + args).flatten.uniq if args_valid? args }
30
+ end
31
+
32
+ def where(*args)
33
+ clone.tap { |r| r.where_values += args.compact.select { |i| args_valid? i } if args_valid? args }
34
+ end
35
+
36
+ def having(*args)
37
+ clone.tap { |r| r.having_values += args if args_valid? args }
38
+ end
39
+
40
+ def limit(value = true)
41
+ clone.tap { |r| r.limit_value = value }
42
+ end
43
+
44
+ def offset(value = true)
45
+ clone.tap { |r| r.offset_value = value }
46
+ end
47
+
48
+ def from(table)
49
+ clone.tap { |r| r.from_value = table }
50
+ end
51
+
52
+ def fresh(val=true)
53
+ clone.tap do |r|
54
+ r.fresh_value = val
55
+ r.reset_queries if r.fresh_value
56
+ end
57
+ end
58
+
59
+ def sql(raw_sql)
60
+ clone.tap { |r| r.raw_sql_value = raw_sql }
61
+ end
62
+
63
+ protected
64
+
65
+ def args_valid?(args)
66
+ args.respond_to?(:empty?) ? !args.empty? : !!args
67
+ end
68
+
69
+ end
@@ -0,0 +1,45 @@
1
+ require 'perry/scopes/conditions'
2
+
3
+ module Perry::Scopes
4
+
5
+ module ClassMethods
6
+
7
+ def scopes
8
+ read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {})
9
+ end
10
+
11
+ def scoped
12
+ current_scope ? relation.merge(current_scope) : relation.clone
13
+ end
14
+
15
+ def scope(name, scope_options={})
16
+ name = name.to_sym
17
+
18
+ # TRP: Define the scope and merge onto the relation
19
+ scopes[name] = lambda do |*args|
20
+ options = scope_options.is_a?(Proc) ? scope_options.call(*args) : scope_options
21
+ if options.is_a?(Hash)
22
+ scoped.apply_finder_options(options)
23
+ else
24
+ scoped.merge(options)
25
+ end
26
+ end
27
+
28
+ # TRP: Bind the above block to a method for easy access
29
+ singleton_class.send(:define_method, name, &scopes[name])
30
+ end
31
+
32
+ end
33
+
34
+ module InstanceMethods
35
+
36
+ end
37
+
38
+ def self.included(receiver)
39
+ receiver.extend ClassMethods
40
+ receiver.send :include, InstanceMethods
41
+
42
+ receiver.extend Conditions
43
+ end
44
+
45
+ end
@@ -0,0 +1,101 @@
1
+
2
+ # TRP: Implementation of this feature was heavily influenced by binarylogic's Searchlogic-2.4.19
3
+ # => http://github.com/binarylogic/searchlogic
4
+ #
5
+ # It is designed to mimick much of the API of searchlogic so that it can be used alongside AR objects utilizing Searchlogic
6
+ # without developer confusion. There are certain features that are skipped because of the nature of Perry.
7
+
8
+ module Perry::Scopes
9
+
10
+ module Conditions
11
+
12
+ COMPARISON_CONDITIONS = {
13
+ :equals => [:is, :eq],
14
+ :does_not_equal => [:not_equal_to, :is_not, :not, :ne],
15
+ :less_than => [:lt, :before],
16
+ :less_than_or_equal_to => [:lte],
17
+ :greater_than => [:gt, :after],
18
+ :greater_than_or_equal_to => [:gte],
19
+ }
20
+
21
+ WILDCARD_CONDITIONS = {
22
+ :like => [:contains, :includes],
23
+ :not_like => [:does_not_include],
24
+ :begins_with => [:bw],
25
+ :not_begin_with => [:does_not_begin_with],
26
+ :ends_with => [:ew],
27
+ :not_end_with => [:does_not_end_with]
28
+ }
29
+
30
+ CONDITIONS = {}
31
+
32
+ # Add any / all variations to every comparison and wildcard condition
33
+ COMPARISON_CONDITIONS.merge(WILDCARD_CONDITIONS).each do |condition, aliases|
34
+ CONDITIONS[condition] = aliases
35
+ CONDITIONS["#{condition}_any".to_sym] = aliases.collect { |a| "#{a}_any".to_sym }
36
+ CONDITIONS["#{condition}_all".to_sym] = aliases.collect { |a| "#{a}_all".to_sym }
37
+ end
38
+
39
+ CONDITIONS[:equals_any] = CONDITIONS[:equals_any] + [:in]
40
+ CONDITIONS[:does_not_equal_all] = CONDITIONS[:does_not_equal_all] + [:not_in]
41
+
42
+ PRIMARY_CONDITIONS = CONDITIONS.keys
43
+ ALIAS_CONDITIONS = CONDITIONS.values.flatten
44
+
45
+ def respond_to?(name, include_private=false)
46
+ super ||
47
+ condition_details(name)
48
+ end
49
+
50
+ private
51
+
52
+ def method_missing(name, *args, &block)
53
+ if details = condition_details(name)
54
+ create_condition(details[:attribute], details[:condition], args)
55
+ send(name, *args)
56
+ else
57
+ super
58
+ end
59
+ end
60
+
61
+ def condition_details(method_name)
62
+ return nil unless defined_attributes
63
+
64
+ attribute_name_matcher = defined_attributes.join("|")
65
+ conditions_matcher = (PRIMARY_CONDITIONS + ALIAS_CONDITIONS).join("|")
66
+
67
+ if method_name.to_s =~ /^(#{attribute_name_matcher})_(#{conditions_matcher})$/
68
+ {:attribute => $1, :condition => $2}
69
+ end
70
+ end
71
+
72
+ def create_condition(attribute, condition, args)
73
+ if PRIMARY_CONDITIONS.include?(condition.to_sym)
74
+ create_primary_condition(attribute, condition)
75
+ elsif ALIAS_CONDITIONS.include?(condition.to_sym)
76
+ create_alias_condition(attribute, condition, args)
77
+ end
78
+ end
79
+
80
+ def create_primary_condition(attribute, condition)
81
+ scope_name = "#{attribute}_#{condition}"
82
+ scope scope_name, lambda { |a| where(scope_name => a) }
83
+ end
84
+
85
+ def create_alias_condition(attribute, condition, args)
86
+ primary_condition = primary_condition(condition)
87
+ alias_name = "#{attribute}_#{condition}"
88
+ primary_name = "#{attribute}_#{primary_condition}"
89
+ send(primary_name, *args) # go back to method_missing and make sure we create the method
90
+ singleton_class.class_eval { alias_method alias_name, primary_name }
91
+ end
92
+
93
+ # Returns the primary condition for the given alias. Ex:
94
+ #
95
+ # primary_condition(:gt) => :greater_than
96
+ def primary_condition(alias_condition)
97
+ CONDITIONS.find { |k, v| k == alias_condition.to_sym || v.include?(alias_condition.to_sym) }.first
98
+ end
99
+ end
100
+
101
+ end
@@ -0,0 +1,48 @@
1
+ require 'yaml'
2
+
3
+ module Perry::Serialization
4
+
5
+ module ClassMethods
6
+
7
+ def serialize(fields)
8
+ [*fields].each do |field|
9
+ serialized_attributes << field
10
+
11
+ define_method("deserialize_#{field}") do
12
+ YAML.load(self[field]) rescue self[field]
13
+ end
14
+
15
+ alias_method "#{field}_raw", field
16
+ alias_method field, "deserialize_#{field}"
17
+
18
+ set_serialize_writers(field) if self.write_adapter
19
+
20
+ end
21
+ end
22
+
23
+ def set_serialize_writers(field)
24
+ define_method("serialize_#{field}") do |value|
25
+ self[field] = value.to_yaml
26
+ end
27
+
28
+ alias_method "#{field}_raw=", "#{field}="
29
+ alias_method "#{field}=", "serialize_#{field}"
30
+ end
31
+
32
+ end
33
+
34
+ module InstanceMethods
35
+
36
+ end
37
+
38
+ def self.included(receiver)
39
+ receiver.class_eval do
40
+ class_inheritable_accessor :serialized_attributes
41
+ self.serialized_attributes = []
42
+ end
43
+
44
+ receiver.extend ClassMethods
45
+ receiver.send :include, InstanceMethods
46
+ end
47
+
48
+ end
@@ -0,0 +1,13 @@
1
+ module Perry
2
+ module Version
3
+
4
+ MAJOR = 0
5
+ MINOR = 4
6
+ TINY = 0
7
+
8
+ def self.to_s # :nodoc:
9
+ [MAJOR, MINOR, TINY].join('.')
10
+ end
11
+
12
+ end
13
+ end
metadata ADDED
@@ -0,0 +1,187 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: perry
3
+ version: !ruby/object:Gem::Version
4
+ hash: 15
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 4
9
+ - 0
10
+ version: 0.4.0
11
+ platform: ruby
12
+ authors:
13
+ - Travis Petticrew
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-04-14 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: shoulda
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 39
30
+ segments:
31
+ - 2
32
+ - 10
33
+ - 0
34
+ version: 2.10.0
35
+ type: :development
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: leftright
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 19
46
+ segments:
47
+ - 0
48
+ - 0
49
+ - 6
50
+ version: 0.0.6
51
+ type: :development
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: fakeweb
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 27
62
+ segments:
63
+ - 1
64
+ - 3
65
+ - 0
66
+ version: 1.3.0
67
+ type: :development
68
+ version_requirements: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ name: factory_girl
71
+ prerelease: false
72
+ requirement: &id004 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ hash: 3
78
+ segments:
79
+ - 0
80
+ version: "0"
81
+ type: :development
82
+ version_requirements: *id004
83
+ - !ruby/object:Gem::Dependency
84
+ name: activesupport
85
+ prerelease: false
86
+ requirement: &id005 !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ hash: 3
92
+ segments:
93
+ - 2
94
+ - 3
95
+ - 0
96
+ version: 2.3.0
97
+ type: :runtime
98
+ version_requirements: *id005
99
+ - !ruby/object:Gem::Dependency
100
+ name: bertrpc
101
+ prerelease: false
102
+ requirement: &id006 !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ hash: 27
108
+ segments:
109
+ - 1
110
+ - 3
111
+ - 0
112
+ version: 1.3.0
113
+ type: :runtime
114
+ version_requirements: *id006
115
+ description:
116
+ email: bobo@petticrew.net
117
+ executables: []
118
+
119
+ extensions: []
120
+
121
+ extra_rdoc_files:
122
+ - README.rdoc
123
+ files:
124
+ - README.rdoc
125
+ - Rakefile
126
+ - lib/perry/adapters/abstract_adapter.rb
127
+ - lib/perry/adapters/bertrpc_adapter.rb
128
+ - lib/perry/adapters/restful_http_adapter.rb
129
+ - lib/perry/adapters.rb
130
+ - lib/perry/association.rb
131
+ - lib/perry/association_preload.rb
132
+ - lib/perry/associations/common.rb
133
+ - lib/perry/associations/contains.rb
134
+ - lib/perry/associations/external.rb
135
+ - lib/perry/base.rb
136
+ - lib/perry/cacheable/entry.rb
137
+ - lib/perry/cacheable/store.rb
138
+ - lib/perry/cacheable.rb
139
+ - lib/perry/core_ext/kernel/singleton_class.rb
140
+ - lib/perry/errors.rb
141
+ - lib/perry/logger.rb
142
+ - lib/perry/persistence.rb
143
+ - lib/perry/relation/finder_methods.rb
144
+ - lib/perry/relation/query_methods.rb
145
+ - lib/perry/relation.rb
146
+ - lib/perry/scopes/conditions.rb
147
+ - lib/perry/scopes.rb
148
+ - lib/perry/serialization.rb
149
+ - lib/perry/version.rb
150
+ - lib/perry.rb
151
+ has_rdoc: true
152
+ homepage: http://github.com/tpett/perry
153
+ licenses: []
154
+
155
+ post_install_message:
156
+ rdoc_options:
157
+ - --main
158
+ - README.rdoc
159
+ require_paths:
160
+ - lib
161
+ required_ruby_version: !ruby/object:Gem::Requirement
162
+ none: false
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ hash: 3
167
+ segments:
168
+ - 0
169
+ version: "0"
170
+ required_rubygems_version: !ruby/object:Gem::Requirement
171
+ none: false
172
+ requirements:
173
+ - - ">="
174
+ - !ruby/object:Gem::Version
175
+ hash: 3
176
+ segments:
177
+ - 0
178
+ version: "0"
179
+ requirements: []
180
+
181
+ rubyforge_project:
182
+ rubygems_version: 1.4.2
183
+ signing_key:
184
+ specification_version: 3
185
+ summary: Ruby library for querying and mapping data through generic interfaces
186
+ test_files: []
187
+