paraphrase 0.3.2 → 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.
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