respond_to_faster 0.0.1 → 0.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9f06087ed36268670b30677984ce24720fe47b07
4
- data.tar.gz: 993129ec0042fa434b31f2a5b3ce49c21248c96d
3
+ metadata.gz: b424a2e779015c87f2875079a8ec8df721c23ac3
4
+ data.tar.gz: d9f71e62dad4f85912e22e4a1cb2922e4e99e3d7
5
5
  SHA512:
6
- metadata.gz: '0929b03566c46db822d280dd117e11b94595435b1d0a99feb58972b1a23c9529d2dfdd21c19c3c898d9bd07bf568805ac89527414d3983867d9b3ad474b7da49'
7
- data.tar.gz: 883278f1fc91b09eb4d2458c705cdd6f9e98ba8b90685e1ad42331c570c076c669b4f6ef25b42c8f4161c02b0c9592fa49c8efaad3b6dbe63b4f96c7c2ccdfe5
6
+ metadata.gz: 1e83e14ed3105dcdbd3c56279873311db4ae60426c64a21f0a7fd8066785a3ed0111fc2b3ace7556f069583568c4895809cfeb507fff4661c900d429beba16e8
7
+ data.tar.gz: e7996d9d301c561e9e64a40cff73e8382eac3919f018f96913111e03a1cebf27ea44d72f34e9439a1c4df4e4afe1e2daef1e72ff1103d42d930e6e4ea6afed22
@@ -0,0 +1,7 @@
1
+ # RespondToFaster Changelog
2
+
3
+ ## 0.1
4
+
5
+ ### 0.1.0
6
+ * Cache modules across singleton classes [#1](https://github.com/shioyama/respond_to_faster/pull/1)
7
+
data/Gemfile CHANGED
@@ -4,3 +4,20 @@ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
5
  # Specify your gem's dependencies in respond_to_faster.gemspec
6
6
  gemspec
7
+
8
+ group :development, :test do
9
+ if ENV['RAILS_VERSION'] == '5.0'
10
+ gem 'activerecord', '>= 5.0', '< 5.1'
11
+ elsif ENV['RAILS_VERSION'] == '4.2'
12
+ gem 'activerecord', '>= 4.2.6', '< 5.0'
13
+ elsif ENV['RAILS_VERSION'] == '5.1'
14
+ gem 'activerecord', '>= 5.1', '< 5.2'
15
+ else
16
+ gem 'activerecord', '>= 5.2.0.beta2', '< 5.3'
17
+ gem 'railties', '>= 5.2.0.beta2', '< 5.3'
18
+ end
19
+
20
+ gem 'benchmark-ips'
21
+ gem 'sqlite3'
22
+ gem 'pry-byebug'
23
+ end
@@ -1,29 +1,76 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- respond_to_faster (0.1.0)
5
- activerecord (>= 5.1, < 6.0)
4
+ respond_to_faster (0.0.1)
5
+ activerecord (>= 5.0, < 6.0)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- activemodel (5.1.4)
11
- activesupport (= 5.1.4)
12
- activerecord (5.1.4)
13
- activemodel (= 5.1.4)
14
- activesupport (= 5.1.4)
15
- arel (~> 8.0)
16
- activesupport (5.1.4)
10
+ actionpack (5.2.0.beta2)
11
+ actionview (= 5.2.0.beta2)
12
+ activesupport (= 5.2.0.beta2)
13
+ rack (~> 2.0)
14
+ rack-test (>= 0.6.3)
15
+ rails-dom-testing (~> 2.0)
16
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
17
+ actionview (5.2.0.beta2)
18
+ activesupport (= 5.2.0.beta2)
19
+ builder (~> 3.1)
20
+ erubi (~> 1.4)
21
+ rails-dom-testing (~> 2.0)
22
+ rails-html-sanitizer (~> 1.0, >= 1.0.3)
23
+ activemodel (5.2.0.beta2)
24
+ activesupport (= 5.2.0.beta2)
25
+ activerecord (5.2.0.beta2)
26
+ activemodel (= 5.2.0.beta2)
27
+ activesupport (= 5.2.0.beta2)
28
+ arel (>= 9.0)
29
+ activesupport (5.2.0.beta2)
17
30
  concurrent-ruby (~> 1.0, >= 1.0.2)
18
31
  i18n (~> 0.7)
19
32
  minitest (~> 5.1)
20
33
  tzinfo (~> 1.1)
21
- arel (8.0.0)
34
+ arel (9.0.0)
35
+ benchmark-ips (2.7.2)
36
+ builder (3.2.3)
37
+ byebug (9.1.0)
38
+ coderay (1.1.2)
22
39
  concurrent-ruby (1.0.5)
40
+ crass (1.0.3)
41
+ database_cleaner (1.6.2)
23
42
  diff-lcs (1.3)
43
+ erubi (1.7.0)
24
44
  i18n (0.9.1)
25
45
  concurrent-ruby (~> 1.0)
46
+ loofah (2.1.1)
47
+ crass (~> 1.0.2)
48
+ nokogiri (>= 1.5.9)
49
+ method_source (0.9.0)
50
+ mini_portile2 (2.3.0)
26
51
  minitest (5.10.3)
52
+ nokogiri (1.8.1)
53
+ mini_portile2 (~> 2.3.0)
54
+ pry (0.11.3)
55
+ coderay (~> 1.1.0)
56
+ method_source (~> 0.9.0)
57
+ pry-byebug (3.5.1)
58
+ byebug (~> 9.1)
59
+ pry (~> 0.10)
60
+ rack (2.0.3)
61
+ rack-test (0.8.2)
62
+ rack (>= 1.0, < 3)
63
+ rails-dom-testing (2.0.3)
64
+ activesupport (>= 4.2.0)
65
+ nokogiri (>= 1.6)
66
+ rails-html-sanitizer (1.0.3)
67
+ loofah (~> 2.0)
68
+ railties (5.2.0.beta2)
69
+ actionpack (= 5.2.0.beta2)
70
+ activesupport (= 5.2.0.beta2)
71
+ method_source
72
+ rake (>= 0.8.7)
73
+ thor (>= 0.18.1, < 2.0)
27
74
  rake (10.5.0)
28
75
  rspec (3.7.0)
29
76
  rspec-core (~> 3.7.0)
@@ -38,6 +85,8 @@ GEM
38
85
  diff-lcs (>= 1.2.0, < 2.0)
39
86
  rspec-support (~> 3.7.0)
40
87
  rspec-support (3.7.0)
88
+ sqlite3 (1.3.13)
89
+ thor (0.20.0)
41
90
  thread_safe (0.3.6)
42
91
  tzinfo (1.2.4)
43
92
  thread_safe (~> 0.1)
@@ -46,10 +95,16 @@ PLATFORMS
46
95
  ruby
47
96
 
48
97
  DEPENDENCIES
49
- bundler (~> 1.16.a)
98
+ activerecord (>= 5.2.0.beta2, < 5.3)
99
+ benchmark-ips
100
+ bundler (~> 1.16)
101
+ database_cleaner (~> 1.6)
102
+ pry-byebug
103
+ railties (>= 5.2.0.beta2, < 5.3)
50
104
  rake (~> 10.0)
51
105
  respond_to_faster!
52
106
  rspec (~> 3.0)
107
+ sqlite3
53
108
 
54
109
  BUNDLED WITH
55
- 1.16.0.pre.2
110
+ 1.16.0
data/README.md CHANGED
@@ -1,22 +1,135 @@
1
- # RespondToFaster :rocket:
1
+ RespondToFaster :rocket:
2
+ ========================
2
3
 
3
- Speed up methods on results from custom ActiveRecord queries.
4
+ [![Gem Version](https://badge.fury.io/rb/respond_to_faster.svg)][gem]
5
+ [![Build Status](https://travis-ci.org/shioyama/respond_to_faster.svg?branch=master)][travis]
6
+ [![Dependency Status](https://gemnasium.com/shioyama/respond_to_faster.svg)][gemnasium]
7
+
8
+ [gem]: https://rubygems.org/gems/respond_to_faster
9
+ [travis]: https://travis-ci.org/shioyama/respond_to_faster
10
+ [gemnasium]: https://gemnasium.com/shioyama/respond_to_faster
11
+
12
+ Speed up method response times on results from custom aliased ActiveRecord
13
+ queries.
4
14
 
5
15
  ## Usage
6
16
 
7
- Suppose you have a query with some custom SQL, like this:
17
+ Just add the gem to your Gemfile:
18
+
19
+ ```ruby
20
+ gem 'respond_to_faster', '~> 0.1.0'
21
+ ```
22
+
23
+ That's it! Read on to learn about what RespondToFaster is doing under the hood
24
+ (or checkout the source code, it's only 20 lines long!)
25
+
26
+ ## Background
27
+
28
+ Suppose you have a query with some custom SQL, like this (taken from the
29
+ [ActiveRecord Querying documentation](http://guides.rubyonrails.org/active_record_querying.html#group)):
30
+
31
+ ```ruby
32
+ Order.select("date(created_at) as ordered_date, sum(price) as total_price").group("date(created_at)")
33
+ ```
34
+
35
+ This query will group orders by date, with each date result responding to the
36
+ aliases `ordered_date` and `total_price`. So if `order` is the first result
37
+ returned, this will work:
38
+
39
+ ```ruby
40
+ order.ordered_date
41
+ #=> Thu, 14 Dec 2017
42
+ order.total_price
43
+ #=> 20.98
44
+ ```
45
+
46
+ This is nice, but are those really methods? Let's have a look:
47
+
48
+ ```ruby
49
+ order.method(:ordered_date)
50
+ #=> NameError: undefined method `ordered_date' for class `#<Class:0x00559df3a8ef30>'
51
+ ```
52
+
53
+ That's strange! No method. So how is the object responding to the
54
+ `ordered_date` message?
55
+
56
+ As usual, Rails is doing some magic under the hood. You can find that magic
57
+ documented in the [inline
58
+ docs](https://github.com/rails/rails/blob/fd1304d2aaf5e21df0aac2e8e3f7becdaad15b19/activemodel/lib/active_model/attribute_methods.rb#L415-L420)
59
+ for `ActiveModel::AttributeMethods`, where there is the somewhat cryptic message:
60
+
61
+ > Allows access to the object attributes, which are held in the hash
62
+ > returned by <tt>attributes</tt>, as though they were first-class
63
+ > methods. So a <tt>Person</tt> class with a <tt>name</tt> attribute can for example use
64
+ > <tt>Person#name</tt> and <tt>Person#name=</tt> and never directly use
65
+ > the attributes hash -- except for multiple assignments with
66
+ > <tt>ActiveRecord::Base#attributes=</tt>.
67
+
68
+ This inline comment dates back to the [very first Rails commit by @dhh in
69
+ 2004](https://github.com/rails/rails/commit/db045dbbf60b53dbe013ef25554fd013baf88134).
70
+
71
+ What the code (now in ActiveModel, previously in ActiveRecord) actually does is
72
+ to override `respond_to?` and `method_missing` to check if a given method call
73
+ matches a key in the `attributes` hash of the model. If there's a match,
74
+ ActiveModel "dispatches" to an attribute handler, which returns the result.
75
+
76
+ Which is all fine and good, but **method_missing is slow as molasses**. You never
77
+ really want to be relying on it to return results unless you have no
78
+ alternative.
79
+
80
+ ## What this gem does
81
+
82
+ So what this gem does is to *remove these overrides*, which have been around
83
+ since the dawn of Ruby on Rails. Not just tweak them, or override them, but
84
+ **remove them**.
85
+
86
+ Here is the code that does this, just two lines:
8
87
 
9
88
  ```ruby
10
- posts = Post.select(:title, :content)
89
+ ActiveModel::AttributeMethods.send(:remove_method, :respond_to?)
90
+ ActiveModel::AttributeMethods.send(:remove_method, :method_missing)
91
+ ```
92
+
93
+ For the vast majority of cases, *this will have no impact on your ActiveRecord
94
+ objects*. AR has grown over the years to the point where most attribute methods
95
+ are defined, so these fallbacks are not necessary.
96
+
97
+ The one exception is the example earlier with the custom aliased query. In this
98
+ case, depending on the query, some custom attributes are needed on the objects
99
+ returned, and ActiveRecord still relies on this (very slow) mechanism to make
100
+ the magic work.
101
+
102
+ But this is a high price to pay for some simple magic. This gem instead
103
+ *defines the methods* on the singleton class of the objects returned, so that
104
+ you never need to go to `method_missing`. This makes things **much faster**, as
105
+ much as 5-10 times faster.
106
+
107
+ ## Caveats
108
+
109
+ If you don't use any custom querying with aliases like the one above, this gem
110
+ might not do much for you. It should make `respond_to?` a bit faster, but you
111
+ may not even notice that.
112
+
113
+ However, if you've got some crazy heavy SQL logic somewhere deep in your
114
+ application, and you're finding it takes forever, give this gem a shot and tell
115
+ me what you find! I'd like to get this eventually merged into ActiveRecord so
116
+ I'd like to know about any issues you encounter in your application.
11
117
 
12
118
  ## Contributing
13
119
 
14
- Bug reports and pull requests are welcome on GitHub at https://github.com/shioyama/respond_to_faster. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
120
+ Bug reports and pull requests are welcome on GitHub at
121
+ https://github.com/shioyama/respond_to_faster. This project is intended to be a
122
+ safe, welcoming space for collaboration, and contributors are expected to
123
+ adhere to the [Contributor Covenant](http://contributor-covenant.org) code of
124
+ conduct.
15
125
 
16
126
  ## License
17
127
 
18
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
128
+ The gem is available as open source under the terms of the [MIT
129
+ License](https://opensource.org/licenses/MIT).
19
130
 
20
131
  ## Code of Conduct
21
132
 
22
- Everyone interacting in the RespondToFaster project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/shioyama/respond_to_faster/blob/master/CODE_OF_CONDUCT.md).
133
+ Everyone interacting in the RespondToFaster project’s codebases, issue
134
+ trackers, chat rooms and mailing lists is expected to follow the [code of
135
+ conduct](https://github.com/shioyama/respond_to_faster/blob/master/CODE_OF_CONDUCT.md).
@@ -1,10 +1,18 @@
1
+ require "active_record"
1
2
  require "respond_to_faster/version"
2
3
 
3
4
  module RespondToFaster
4
5
  def init_with(coder)
5
6
  super.tap do
6
- (attribute_names - self.class.attribute_names).each do |name|
7
- singleton_class.define_attribute_method name
7
+ unless (uncached_attrs = attribute_names - self.class.attribute_names).empty?
8
+ klass = self.class
9
+ mod_name = "RespondToFaster_#{uncached_attrs.hash.abs}".freeze
10
+ if klass.const_defined?(mod_name)
11
+ singleton_class.include klass.const_get(mod_name)
12
+ else
13
+ uncached_attrs.each &singleton_class.method(:define_attribute_method)
14
+ klass.const_set(mod_name, singleton_class.send(:generated_attribute_methods))
15
+ end
8
16
  end
9
17
  end
10
18
  end
@@ -1,3 +1,3 @@
1
1
  module RespondToFaster
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: respond_to_faster
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Salzberg
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-12-18 00:00:00.000000000 Z
11
+ date: 2017-12-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,7 +16,7 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '5.1'
19
+ version: '5.0'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
22
  version: '6.0'
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: '5.1'
29
+ version: '5.0'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '6.0'
@@ -72,6 +72,20 @@ dependencies:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
74
  version: '3.0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: database_cleaner
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '1.6'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '1.6'
75
89
  description: Patches ActiveRecord to make models returned from custom queries respond
76
90
  much faster.
77
91
  email:
@@ -80,6 +94,7 @@ executables: []
80
94
  extensions: []
81
95
  extra_rdoc_files: []
82
96
  files:
97
+ - CHANGELOG.md
83
98
  - CODE_OF_CONDUCT.md
84
99
  - Gemfile
85
100
  - Gemfile.lock