paraphrase 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,10 @@
1
+ 0.4.0 / 7-6-2012
2
+
3
+ * Setup Query#params to be HashWithIndifferentAccess.
4
+ * Gut out Paraphrase module methods. These were for use cases I had planned
5
+ for but have yet to encounter.
6
+ * Model's query class is now stored on the model itself.
7
+
1
8
  0.3.2 / 7-5-2012
2
9
 
3
10
  * Cache Query#results
data/README.md CHANGED
@@ -29,8 +29,7 @@ $ gem install paraphrase
29
29
 
30
30
  ### Setup
31
31
 
32
- paraphrase aims to be as flexible as possible. `Query` classes can be created
33
- in the following ways:
32
+ `Paraphrase::Query` classes can be created in the following ways:
34
33
 
35
34
  * Calling `register_mapping` in an `ActiveRecord::Base` subclass:
36
35
 
@@ -46,23 +45,12 @@ class Post < ActiveRecord::Base
46
45
  end
47
46
  ```
48
47
 
49
- * A configuration block through `Paraphrase.configure`:
50
-
51
- ```ruby
52
- # config/initializers/paraphrase.rb
53
-
54
- Paraphrase.configure do |mappings|
55
- mappings.register :post do
56
- paraphrases Post
57
- scope :by_user, :key => :author
58
- end
59
- end
60
- ```
61
-
62
48
  * Subclassing `Paraphrase::Query`:
63
49
 
64
50
  ```ruby
65
51
  class PostQuery < Paraphrase::Query
52
+ # takes the constant or a symbol/string that can be classified
53
+ # into a constant name
66
54
  paraphrases Post
67
55
 
68
56
  scope :by_user, :key => :author
@@ -79,11 +67,7 @@ class PostsController < ApplicationController
79
67
 
80
68
  def index
81
69
  @posts = Post.paraphrase(params)
82
-
83
- # Or
84
- # @posts = Paraphrase.query(:post, params)
85
-
86
- # If you created a subclass
70
+ # Or if you created a subclass
87
71
  # @posts = PostQuery.new(params)
88
72
 
89
73
  respond_with(@posts)
@@ -1,4 +1,3 @@
1
1
  module Paraphrase
2
- class DuplicateMappingError < StandardError; end
3
2
  class DuplicateScopeError < StandardError; end
4
3
  end
@@ -1,6 +1,7 @@
1
- require 'active_support/core_ext/class/attribute_accessors'
2
1
  require 'active_support/core_ext/class/attribute'
3
2
  require 'active_support/core_ext/module/delegation'
3
+ require 'active_support/core_ext/string/inflections'
4
+ require 'active_support/hash_with_indifferent_access'
4
5
  require 'active_model/naming'
5
6
 
6
7
  module Paraphrase
@@ -12,8 +13,7 @@ module Paraphrase
12
13
  #
13
14
  # @!attribute [r] source
14
15
  # @return [ActiveRecord::Relation] source to apply scopes to
15
- cattr_reader :scopes, :source
16
- @@scopes = []
16
+ class_attribute :scopes, :source, :instance_writer => false
17
17
 
18
18
 
19
19
  # Delegate enumerable methods to results
@@ -24,10 +24,16 @@ module Paraphrase
24
24
  # @return [ActiveModel::Errors] errors from determining results
25
25
  #
26
26
  # @!attribute [r] params
27
- # @return [Hash] filters parameters based on keys defined in scopes
27
+ # @return [HashWithIndifferentAccess] filters parameters based on keys defined in scopes
28
28
  attr_reader :errors, :params
29
29
 
30
30
 
31
+ # Set `scopes` on inheritance to ensure they're unique per subclass
32
+ def self.inherited(klass)
33
+ klass.scopes = []
34
+ end
35
+
36
+
31
37
  # Specify the ActiveRecord model to use as the source for queries
32
38
  #
33
39
  # @param [String, Symbol, ActiveRecord::Base] klass name of the class to
@@ -37,9 +43,7 @@ module Paraphrase
37
43
  klass = Object.const_get(klass.to_s.classify)
38
44
  end
39
45
 
40
- @@source = klass.scoped
41
-
42
- Paraphrase.add(klass.name, self)
46
+ self.source = klass
43
47
  end
44
48
 
45
49
 
@@ -47,11 +51,11 @@ module Paraphrase
47
51
  #
48
52
  # @see ScopeMapping#initialize
49
53
  def self.scope(name, options)
50
- if @@scopes.map(&:method_name).include?(name)
54
+ if scopes.map(&:method_name).include?(name)
51
55
  raise DuplicateScopeError, "scope :#{name} has already been added"
52
56
  end
53
57
 
54
- @@scopes << ScopeMapping.new(name, options)
58
+ scopes << ScopeMapping.new(name, options)
55
59
  end
56
60
 
57
61
 
@@ -59,8 +63,8 @@ module Paraphrase
59
63
  #
60
64
  # @param [Hash] params query parameters
61
65
  def initialize(params = {})
62
- keys = scopes.map(&:param_keys).flatten
63
- @params = params.dup
66
+ keys = scopes.map(&:param_keys).flatten.map(&:to_s)
67
+ @params = HashWithIndifferentAccess.new(params)
64
68
  @params.select! { |key, value| keys.include?(key) }
65
69
  @params.freeze
66
70
 
@@ -73,13 +77,13 @@ module Paraphrase
73
77
  #
74
78
  # @return [ActiveRecord::Relation, Array]
75
79
  def results
76
- @results ||= begin
77
- results = scopes.inject(source) do |query, scope|
78
- scope.chain(self, @params, query)
79
- end
80
+ return @results if @results
81
+
82
+ results = scopes.inject(source.scoped) do |query, scope|
83
+ scope.chain(self, @params, query)
84
+ end
80
85
 
81
- @errors.any? ? [] : results
82
- end
86
+ @results = @errors.any? ? [] : results
83
87
  end
84
88
 
85
89
 
@@ -1,18 +1,21 @@
1
1
  module Paraphrase
2
2
  module Syntax
3
3
 
4
+ def self.extended(klass)
5
+ klass.instance_eval do
6
+ class_attribute :paraphraser, :instance_writer => false, :instance_reader => false
7
+ end
8
+ end
9
+
4
10
  # Register a {Query} class mapped to `self`. If the mapping has already
5
11
  # been registered, calling again will clear existing scopes and evaluate
6
12
  # the block.
7
13
  #
8
14
  # @param [Proc] &block block to define scope mappings
9
15
  def register_mapping(&block)
10
- if mapping = Paraphrase.mapping(self.name.underscore)
11
- mapping.scopes.clear
12
- mapping.instance_eval(&block)
13
- else
14
- Paraphrase.register(self.name, &block)
15
- end
16
+ klass = Class.new(Query, &block)
17
+ klass.source = self
18
+ self.paraphraser = klass
16
19
  end
17
20
 
18
21
 
@@ -20,7 +23,7 @@ module Paraphrase
20
23
  #
21
24
  # @param [Hash] params query parameters
22
25
  def paraphrase(params)
23
- Paraphrase.query(self.name.underscore, params)
26
+ self.paraphraser.new(params)
24
27
  end
25
28
  end
26
29
  end
@@ -1,3 +1,3 @@
1
1
  module Paraphrase
2
- VERSION = "0.3.2"
2
+ VERSION = "0.4.0"
3
3
  end
data/lib/paraphrase.rb CHANGED
@@ -1,64 +1,3 @@
1
- require 'active_support/core_ext/module/attribute_accessors'
2
- require 'active_support/core_ext/hash/indifferent_access'
3
- require 'active_support/core_ext/string/inflections'
4
-
5
- module Paraphrase
6
-
7
- @@mappings = {}.with_indifferent_access
8
-
9
- # Allows for configuring multiple {Query} classes in a single block. Useful
10
- # in an initializer.
11
- def self.configure(&block)
12
- yield self
13
- end
14
-
15
-
16
- # Retreive a registered Query subclass.
17
- #
18
- # @param [String, Symbol] name of the class underscored
19
- # @return [Query]
20
- def self.mapping(name)
21
- @@mappings[name]
22
- end
23
-
24
-
25
- # Add a new subclass of Paraprhase::Query. The provided block is evaluated in
26
- # the context of a Query subclass to define scope mappings.
27
- #
28
- # @param [String, Symbol] name name of the model in any inflector form
29
- # @param [Proc] block defining mappings of scopes to keys for Query subclass
30
- def self.register(name, &block)
31
- klass = Class.new(Query, &block)
32
- klass.paraphrases(name.to_s.classify)
33
- end
34
-
35
-
36
- # Register a subclass of Paraphrase::Query. Useful for manually subclassing
37
- # Paraphrase::Query to add custom functionality.
38
- #
39
- # @param [String, Symbol] name name of the class in any ActiveSupport inflector form
40
- # @param [Query] klass subclass of Paraphrase::Query
41
- def self.add(name, klass)
42
- name = name.to_s.underscore
43
-
44
- if @@mappings[name]
45
- raise DuplicateMappingError, "#{name.classify} has already been added"
46
- end
47
-
48
- @@mappings[name] = klass
49
- end
50
-
51
-
52
- # Instantiate a new Query subclass using supplied params
53
- #
54
- # @param [String, Symbol] name name of the model in underscored form
55
- # @param [Hash] params hash of query params
56
- # @return [Query]
57
- def self.query(name, params)
58
- @@mappings[name].new(params)
59
- end
60
- end
61
-
62
1
  require 'paraphrase/errors'
63
2
  require 'paraphrase/query'
64
3
  require 'paraphrase/syntax'
@@ -5,55 +5,55 @@ module Paraphrase
5
5
 
6
6
  describe ".paraphrases" do
7
7
  it "stores the class being queried" do
8
- UserSearch.paraphrases :user
9
- UserSearch.source.should eq User.scoped
10
- end
11
-
12
- it "registers the query in Paraphrase.querys" do
13
- Paraphrase.mapping(:user).should eq UserSearch
8
+ AccountSearch.paraphrases :account
9
+ AccountSearch.source.should eq Account
14
10
  end
15
11
  end
16
12
 
17
13
  describe ".scope" do
18
14
  it "adds information to Query.scopes" do
19
- UserSearch.instance_eval do
15
+ AccountSearch.instance_eval do
20
16
  scope :name_like, :key => :name
21
17
  end
22
18
 
23
- UserSearch.scopes.should_not be_empty
19
+ AccountSearch.scopes.should_not be_empty
24
20
  end
25
21
 
26
22
  it "raises an error if a scope is added twice" do
27
- expect { UserSearch.instance_eval { scope :name_like, :key => :name } }.to raise_error Paraphrase::DuplicateScopeError
23
+ expect { AccountSearch.instance_eval { scope :name_like, :key => :name } }.to raise_error Paraphrase::DuplicateScopeError
28
24
  end
29
25
  end
30
26
 
31
27
  describe "#initialize" do
32
- it "filters out params not specified in scopes" do
33
- query = UserSearch.new(:name => 'Tyrion Lannister', :nickname => 'Half Man')
28
+ let(:query) { AccountSearch.new(:name => 'Tyrion Lannister', :nickname => 'Half Man') }
34
29
 
30
+ it "filters out params not specified in scopes" do
35
31
  query.params.should_not have_key :nickname
36
32
  query.params.should have_key :name
37
33
  end
34
+
35
+ it "sets up params with indifferent access" do
36
+ query.params.should have_key 'name'
37
+ end
38
38
  end
39
39
 
40
40
  describe "#results" do
41
41
  before :all do
42
- UserSearch.instance_eval do
42
+ AccountSearch.instance_eval do
43
43
  scope :title_like, :key => :title, :require => true
44
44
  end
45
45
  end
46
46
 
47
47
  it "loops through scope methods and applies them to source" do
48
- User.should_receive(:title_like).and_return(User.scoped)
49
- User.should_receive(:name_like).and_return(User.scoped)
48
+ Account.should_receive(:title_like).and_return(Account.scoped)
49
+ Account.should_receive(:name_like).and_return(Account.scoped)
50
50
 
51
- query = UserSearch.new(:name => 'Jon Snow', :title => 'Wall Watcher')
51
+ query = AccountSearch.new(:name => 'Jon Snow', :title => 'Wall Watcher')
52
52
  query.results
53
53
  end
54
54
 
55
55
  it "returns empty array if errors were added" do
56
- query = UserSearch.new
56
+ query = AccountSearch.new
57
57
  query.results.should eq []
58
58
  query.errors.should_not be_empty
59
59
  end
@@ -4,24 +4,8 @@ module Paraphrase
4
4
  describe Syntax do
5
5
  describe ".register_mapping" do
6
6
  it "forwards to Paraphrase.register" do
7
- ::Account.register_mapping {}
8
- Paraphrase.mapping(:account).should_not be_nil
9
- end
10
-
11
- it "updates scopes if already registered" do
12
- ::Account.register_mapping do
13
- scope :name_like, :key => :name
14
- end
15
-
16
- mapping = Paraphrase.mapping(:account)
17
- mapping.scopes.should_not be_empty
18
- end
19
- end
20
-
21
- describe ".paraphrase" do
22
- it "forwards to Paraphrase.query" do
23
- Paraphrase.should_receive(:query).with('account', {})
24
- ::Account.paraphrase({})
7
+ Account.register_mapping {}
8
+ Account.paraphraser.should_not be_nil
25
9
  end
26
10
  end
27
11
  end
data/spec/spec_helper.rb CHANGED
@@ -11,25 +11,13 @@ ActiveRecord::Base.silence do
11
11
  ActiveRecord::Migration.verbose = false
12
12
 
13
13
  ActiveRecord::Schema.define do
14
- create_table(:users, :force => true) {}
15
14
  create_table(:accounts, :force => true) {}
16
- create_table(:foobars, :force => true) {}
17
- create_table(:people, :force => true) {}
18
15
  end
19
16
  end
20
17
 
21
- class Person < ActiveRecord::Base
22
- end
23
-
24
- class Foobar < ActiveRecord::Base
25
- end
26
-
27
18
  class Account < ActiveRecord::Base
28
19
  extend Paraphrase::Syntax
29
20
  end
30
21
 
31
- class User < ActiveRecord::Base
32
- end
33
-
34
- class UserSearch < Paraphrase::Query
22
+ class AccountSearch < Paraphrase::Query
35
23
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paraphrase
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-05 00:00:00.000000000 Z
12
+ date: 2012-07-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
16
- requirement: &70289301081080 !ruby/object:Gem::Requirement
16
+ requirement: &70360247937200 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '3.0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70289301081080
24
+ version_requirements: *70360247937200
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: activesupport
27
- requirement: &70289301078480 !ruby/object:Gem::Requirement
27
+ requirement: &70360247936360 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '3.0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70289301078480
35
+ version_requirements: *70360247936360
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: activemodel
38
- requirement: &70289301077280 !ruby/object:Gem::Requirement
38
+ requirement: &70360247934800 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '3.0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70289301077280
46
+ version_requirements: *70360247934800
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: bundler
49
- requirement: &70289301067840 !ruby/object:Gem::Requirement
49
+ requirement: &70360247926020 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '1.0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70289301067840
57
+ version_requirements: *70360247926020
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: yard
60
- requirement: &70289301066540 !ruby/object:Gem::Requirement
60
+ requirement: &70360247925260 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0.7'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70289301066540
68
+ version_requirements: *70360247925260
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
- requirement: &70289301064900 !ruby/object:Gem::Requirement
71
+ requirement: &70360247924500 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ~>
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '2.10'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *70289301064900
79
+ version_requirements: *70360247924500
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: redcarpet
82
- requirement: &70289301064000 !ruby/object:Gem::Requirement
82
+ requirement: &70360247923780 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: '0'
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *70289301064000
90
+ version_requirements: *70360247923780
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: rake
93
- requirement: &70289301063120 !ruby/object:Gem::Requirement
93
+ requirement: &70360247922620 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: '0'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *70289301063120
101
+ version_requirements: *70360247922620
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: sqlite3
104
- requirement: &70289301061980 !ruby/object:Gem::Requirement
104
+ requirement: &70360247921580 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ! '>='
@@ -109,10 +109,10 @@ dependencies:
109
109
  version: '0'
110
110
  type: :development
111
111
  prerelease: false
112
- version_requirements: *70289301061980
112
+ version_requirements: *70360247921580
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: appraisal
115
- requirement: &70289301061200 !ruby/object:Gem::Requirement
115
+ requirement: &70360247921160 !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements:
118
118
  - - ! '>='
@@ -120,7 +120,7 @@ dependencies:
120
120
  version: '0'
121
121
  type: :development
122
122
  prerelease: false
123
- version_requirements: *70289301061200
123
+ version_requirements: *70360247921160
124
124
  description: ! "\n Build customizable classes to determine
125
125
  which scope\n methods to call based on supplied parameters.\n
126
126
  \ "
@@ -155,7 +155,6 @@ files:
155
155
  - spec/paraphrase/query_spec.rb
156
156
  - spec/paraphrase/scope_mapping_spec.rb
157
157
  - spec/paraphrase/syntax_spec.rb
158
- - spec/paraphrase_spec.rb
159
158
  - spec/spec_helper.rb
160
159
  homepage: https://github.com/ecbypi/paraphrase
161
160
  licenses:
@@ -186,6 +185,5 @@ test_files:
186
185
  - spec/paraphrase/query_spec.rb
187
186
  - spec/paraphrase/scope_mapping_spec.rb
188
187
  - spec/paraphrase/syntax_spec.rb
189
- - spec/paraphrase_spec.rb
190
188
  - spec/spec_helper.rb
191
189
  has_rdoc:
@@ -1,43 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Paraphrase do
4
-
5
- describe ".configure" do
6
- it "is a convenience method for configuring multiple query classes" do
7
- Paraphrase.configure do |mapping|
8
- mapping.register(:person) {}
9
- end
10
-
11
- Paraphrase.mapping(:person).should_not be_nil
12
- end
13
- end
14
-
15
- describe ".register" do
16
- it "a sublcass of Paraphrase::Query to @@mappings" do
17
- Paraphrase.register(:foobar) {}
18
- Paraphrase.mapping(:foobar).should_not be_nil
19
- end
20
-
21
- it "adds the source to the new subclass" do
22
- Paraphrase.mapping(:foobar).source.should eq Foobar.scoped
23
- end
24
-
25
- it "raises an error if mappings for a class are added twice" do
26
- expect { Paraphrase.register(:foobar) {} }.to raise_error Paraphrase::DuplicateMappingError
27
- end
28
- end
29
-
30
- describe ".query" do
31
- it "instantiates a new Query class" do
32
- Paraphrase.query(:foobar, {}).should be_a Paraphrase::Query
33
- end
34
- end
35
-
36
- describe ".add" do
37
- it "adds class to mapping with specified name" do
38
- klass = Class.new(Paraphrase::Query)
39
- Paraphrase.add(:baz, klass)
40
- Paraphrase.mapping(:baz).should eq klass
41
- end
42
- end
43
- end