constructorio 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b12777162afb00778087eb0373df3a9c1afa2968
4
+ data.tar.gz: fd37598d4857e6353a863a739c842158a41893d0
5
+ SHA512:
6
+ metadata.gz: 9538982e4bda8b25c18d963f17d33ab89b5e82d4eb06cf061e060049fdda1de1d4b1b04cf846ecabc45ddad92d3cbc4557ad7e95196cdcc5ff3d5389295077ba
7
+ data.tar.gz: 666f30871f099f656f8b536656196b7f615c6a728ea2357544e041422b7b1ca8fabf2a308720b2e624fadcf03df64b3486852b6d36747a13b9f3b855e06f9d10
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ vendor/
data/.rock.yml ADDED
@@ -0,0 +1,10 @@
1
+ runtime: ruby21
2
+
3
+ env:
4
+ PATH: "${ROCK_PATH}/bin:${PATH}"
5
+
6
+ build: |
7
+ rm -f ./bin/bundle
8
+ {{ parent }}
9
+
10
+ run_web: bin/rails s
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in constructorio.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Steven Lai
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # Constructor.io
2
+
3
+ A Ruby client for the [Constructor.io API](http://constructor.io/docs). Constructor.io provides a lightning-fast, typo-tolerant autocomplete service that ranks your users' queries by popularity to let them find what they're looking for as quickly as possible.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'constructorio'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself:
16
+
17
+ $ gem install customerio
18
+
19
+ ## Usage
20
+
21
+ ### Configuration for Rails
22
+
23
+ Add an initializer file at config/initializers/constructor-io.rb with values from the [customer dashboard](http://constructor.io/dashboard):
24
+ ```
25
+ ConstructorIO.configure do |config|
26
+ config.api_token = 'API_TOKEN'
27
+ config.autocomplete_key = 'AUTOCOMPLETE_KEY'
28
+ end
29
+ ```
30
+ To add autocomplete to a model:
31
+
32
+ ```
33
+ class MyModel < ActiveRecord::Base
34
+ extend ConstructorIO
35
+ autocomplete(['attribute1', 'attribute2'])
36
+ end
37
+
38
+ ```
39
+
40
+ To attach an autocomplete dropdown to an input field, just insert this in your view:
41
+
42
+ ```
43
+ <%= autocomplete(dom_id: 'id_of_input_field') %>
44
+ ```
45
+
46
+ To import an existing data set into Constructor.io, you can use the rake task:
47
+
48
+ ```
49
+ rake constructorio:import:model CLASS='MyModel'
50
+ ```
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs.push 'test'
6
+ t.pattern = 'test/**/*_test.rb'
7
+ end
8
+
9
+ task :default => :test
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'constructorio/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "constructorio"
8
+ spec.version = ConstructorIO::VERSION
9
+ spec.authors = ["Steven Lai"]
10
+ spec.email = ["lai.steven@gmail.com"]
11
+ spec.summary = %q{Ruby gem for Constructor.io}
12
+ spec.description = %q{Ruby gem for Constructor.io's autocomplete service. Enables Rails models to send updates to the Constructor.io API automatically, and provides a view helper to add autocomplete on any input.}
13
+ spec.homepage = "http://constructor.io"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "activerecord"
22
+ spec.add_dependency 'faraday', '~> 0.9', '>= 0.9.1'
23
+ spec.add_dependency "activesupport", "~> 3.2"
24
+ spec.add_development_dependency "bundler", "~> 1.7"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency 'pry', '~> 0.10', '>= 0.10.1'
27
+ spec.add_development_dependency 'sqlite3', '~> 1.3', '>= 1.3.10'
28
+ spec.add_development_dependency 'mocha', '~> 1.1', '>= 1.1.0'
29
+ spec.add_development_dependency "minitest", "~> 5.5.1"
30
+ end
@@ -0,0 +1,5 @@
1
+ module ConstructorIO
2
+ class Configuration
3
+ attr_accessor :api_token, :autocomplete_key, :api_url
4
+ end
5
+ end
@@ -0,0 +1,27 @@
1
+ require 'singleton'
2
+
3
+ module ConstructorIO
4
+ class Fields
5
+ include Singleton
6
+
7
+ attr_accessor :set
8
+
9
+ def initialize
10
+ @set = {}
11
+ end
12
+
13
+ def add(model, field)
14
+ @set[model] ||= {}
15
+ @set[model][field] = 1
16
+ end
17
+
18
+ def list(model_name)
19
+ if @set[model_name].is_a?(Hash)
20
+ @set[model_name].keys
21
+ else
22
+ []
23
+ end
24
+ end
25
+ end
26
+ end
27
+
@@ -0,0 +1,11 @@
1
+ # usage: <%= autocomplete :dom_id => "search" %>
2
+
3
+ module ConstructorIO
4
+ module Helper
5
+ def autocomplete(options = {})
6
+ result = %Q|<script type="text/javascript" src="//cnstrc.com/js/ac.js"></script>\n|
7
+ result += %Q|<script>$(document).ready(function(){ $('##{options[:dom_id]}').constructorAutocomplete({ key: '#{ConstructorIO.configuration.autocomplete_key}' }); })</script>|
8
+ return result.html_safe
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ require 'rails'
2
+
3
+ module ConstructorIO
4
+ class Railtie < Rails::Railtie
5
+ initializer 'constructorio.action_view' do
6
+ ActiveSupport.on_load(:action_view) do
7
+ include ConstructorIO::Helper
8
+ end
9
+ end
10
+
11
+ rake_tasks do
12
+ Dir[File.join(File.dirname(__FILE__),'tasks/*.rake')].each { |f| load f }
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ namespace :constructorio do
2
+ import_model_desc = <<-DESC.gsub(/ /, '')
3
+ Import data from your model (pass name as CLASS environment variable).
4
+
5
+ $ rake environment constructorio:import:model CLASS='MyModel'
6
+ DESC
7
+
8
+ task :import => 'import:model'
9
+
10
+ namespace :import do
11
+ desc import_model_desc
12
+
13
+ task :model do
14
+ klass = eval(ENV['CLASS'].to_s)
15
+ fields = ConstructorIO::Fields.instance.list(klass.model_name)
16
+ if fields.any?
17
+ klass.all.each do |record|
18
+ fields.each do |field|
19
+ klass.add_record(record[field.to_sym], ConstructorIO.configuration.autocomplete_key)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ module ConstructorIO
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,75 @@
1
+ require 'constructorio/version'
2
+ require 'constructorio/configuration'
3
+ require 'constructorio/helper'
4
+ require 'constructorio/fields'
5
+ require 'active_record'
6
+ require 'faraday'
7
+ require 'active_support/core_ext/string/output_safety'
8
+
9
+ require 'constructorio/railtie' if defined?(Rails)
10
+
11
+ begin
12
+ require 'pry'
13
+ rescue LoadError
14
+ end
15
+
16
+ module ConstructorIO
17
+ class << self
18
+ attr_accessor :configuration
19
+ end
20
+
21
+ def self.configuration
22
+ @configuration ||= Configuration.new
23
+ end
24
+
25
+ def self.configure
26
+ yield(configuration)
27
+ end
28
+
29
+ def autocomplete(fields, autocomplete_key = ConstructorIO.configuration.autocomplete_key)
30
+
31
+ fields.each do |field|
32
+ ConstructorIO::Fields.instance.add(self.model_name, field)
33
+ end
34
+
35
+ after_save do |record|
36
+ updated_fields = record.changed.select { |c| fields.include? c }
37
+ updated_fields.each do |field|
38
+ record.class.send(:add_record, record[field.to_sym], autocomplete_key)
39
+ end
40
+ end
41
+
42
+ before_destroy do |record|
43
+ fields.each do |field|
44
+ record.class.send(:delete_record, record[field.to_sym], autocomplete_key)
45
+ end
46
+ end
47
+ end
48
+
49
+ def add_record(value, autocomplete_key)
50
+ call_api("post", value, autocomplete_key)
51
+ end
52
+
53
+ def delete_record(value, autocomplete_key)
54
+ call_api("delete", value, autocomplete_key)
55
+ end
56
+
57
+ private
58
+
59
+ def call_api(method, value, autocomplete_key)
60
+ @api_token = ConstructorIO.configuration.api_token
61
+ @api_url = ConstructorIO.configuration.api_url || "https://ac.constructor.io/"
62
+ @http_client ||= Faraday.new(url: @api_url)
63
+ @http_client.basic_auth(@api_token, '')
64
+ response = @http_client.send(method) do |request|
65
+ request.url "/v1/item?autocomplete_key=#{autocomplete_key}"
66
+ request.headers['Content-Type'] = 'application/json'
67
+ request.body = %Q|{"item_name": "#{value}"}|
68
+ end
69
+ if response.status.to_s =~ /^2/
70
+ return nil
71
+ else
72
+ return response.status
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,15 @@
1
+ require_relative 'test_helper'
2
+
3
+ class ConfigurationTest < MiniTest::Test
4
+ def test_configure_api_token
5
+ assert_equal ConstructorIO.configuration.api_token, "example_api_token"
6
+ end
7
+
8
+ def test_configure_autocomplete_key
9
+ assert_equal ConstructorIO.configuration.autocomplete_key, "example_autocomplete_key"
10
+ end
11
+
12
+ def test_configure_api_url
13
+ assert_equal ConstructorIO.configuration.api_url, "http://example.constructor.io"
14
+ end
15
+ end
@@ -0,0 +1,48 @@
1
+ require_relative 'test_helper'
2
+
3
+ class ConstructorIOTest < MiniTest::Test
4
+ def test_add_record
5
+ person = Person.new(
6
+ first_name: "Steven",
7
+ last_name: "Lai",
8
+ address: "New York"
9
+ )
10
+ Person.expects(:call_api).with("post", "Steven", "person_autocomplete_key")
11
+
12
+ assert person.save
13
+ end
14
+
15
+ def test_delete_record
16
+ Person.expects(:call_api).with("post", "Ronald", "person_autocomplete_key")
17
+ person = Person.create(
18
+ first_name: "Ronald",
19
+ last_name: "McDonald",
20
+ address: "Disneyland"
21
+ )
22
+
23
+ Person.expects(:call_api).with("delete", "Ronald", "person_autocomplete_key")
24
+ person.destroy
25
+ end
26
+
27
+ def test_add_record_without_key
28
+ person = PersonNoKey.new(
29
+ first_name: "Steven",
30
+ last_name: "Lai",
31
+ address: "New York"
32
+ )
33
+
34
+ PersonNoKey.expects(:call_api).with("post", "Lai", ConstructorIO.configuration.autocomplete_key)
35
+ assert person.save
36
+ end
37
+
38
+ def test_fields
39
+ Person.expects(:call_api).with("post", "Ronald", "person_autocomplete_key")
40
+ person = Person.create(
41
+ first_name: "Ronald",
42
+ last_name: "McDonald",
43
+ address: "Disneyland"
44
+ )
45
+
46
+ assert_equal ConstructorIO::Fields.instance.list("Person"), ["first_name"]
47
+ end
48
+ end
@@ -0,0 +1,42 @@
1
+ require 'minitest/autorun'
2
+ require 'minitest/unit'
3
+ require 'mocha/mini_test'
4
+ require_relative '../lib/constructorio'
5
+
6
+
7
+ ActiveRecord::Base.establish_connection(
8
+ adapter: 'sqlite3',
9
+ database: ':memory:'
10
+ )
11
+
12
+ ActiveRecord::Schema.define do
13
+ create_table :people, force: true do |t|
14
+ t.string :first_name
15
+ t.string :last_name
16
+ t.string :address
17
+ end
18
+ end
19
+
20
+ ConstructorIO.configure do |config|
21
+ config.api_token = "example_api_token"
22
+ config.autocomplete_key = "example_autocomplete_key"
23
+ config.api_url = "http://example.constructor.io"
24
+ end
25
+
26
+ class Person < ActiveRecord::Base
27
+ extend ConstructorIO
28
+
29
+ autocomplete ['first_name'], "person_autocomplete_key"
30
+ end
31
+
32
+ class PersonNoKey < ActiveRecord::Base
33
+ self.table_name = 'people'
34
+
35
+ extend ConstructorIO
36
+
37
+ autocomplete ['last_name']
38
+ end
39
+
40
+ class FakeView
41
+ include ConstructorIO::Helper
42
+ end
@@ -0,0 +1,11 @@
1
+ require_relative 'test_helper'
2
+
3
+ class ViewHelperTest < MiniTest::Test
4
+ def setup
5
+ @fakeview = FakeView.new
6
+ end
7
+
8
+ def test_autocomplete_html
9
+ assert_equal @fakeview.autocomplete(dom_id: 'a'), "<script type=\"text/javascript\" src=\"//cnstrc.com/js/ac.js\"></script>\n<script>$(document).ready(function(){ $('#a').constructorAutocomplete({ key: 'example_autocomplete_key' }); })</script>"
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,219 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: constructorio
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Steven Lai
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-04-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: faraday
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.9'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 0.9.1
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '0.9'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 0.9.1
47
+ - !ruby/object:Gem::Dependency
48
+ name: activesupport
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '3.2'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '3.2'
61
+ - !ruby/object:Gem::Dependency
62
+ name: bundler
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.7'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '1.7'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rake
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '10.0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '10.0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: pry
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '0.10'
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: 0.10.1
99
+ type: :development
100
+ prerelease: false
101
+ version_requirements: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - "~>"
104
+ - !ruby/object:Gem::Version
105
+ version: '0.10'
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: 0.10.1
109
+ - !ruby/object:Gem::Dependency
110
+ name: sqlite3
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: '1.3'
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: 1.3.10
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - "~>"
124
+ - !ruby/object:Gem::Version
125
+ version: '1.3'
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: 1.3.10
129
+ - !ruby/object:Gem::Dependency
130
+ name: mocha
131
+ requirement: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - "~>"
134
+ - !ruby/object:Gem::Version
135
+ version: '1.1'
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: 1.1.0
139
+ type: :development
140
+ prerelease: false
141
+ version_requirements: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '1.1'
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: 1.1.0
149
+ - !ruby/object:Gem::Dependency
150
+ name: minitest
151
+ requirement: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - "~>"
154
+ - !ruby/object:Gem::Version
155
+ version: 5.5.1
156
+ type: :development
157
+ prerelease: false
158
+ version_requirements: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - "~>"
161
+ - !ruby/object:Gem::Version
162
+ version: 5.5.1
163
+ description: Ruby gem for Constructor.io's autocomplete service. Enables Rails models
164
+ to send updates to the Constructor.io API automatically, and provides a view helper
165
+ to add autocomplete on any input.
166
+ email:
167
+ - lai.steven@gmail.com
168
+ executables: []
169
+ extensions: []
170
+ extra_rdoc_files: []
171
+ files:
172
+ - ".gitignore"
173
+ - ".rock.yml"
174
+ - ".rspec"
175
+ - Gemfile
176
+ - LICENSE.txt
177
+ - README.md
178
+ - Rakefile
179
+ - constructorio.gemspec
180
+ - lib/constructorio.rb
181
+ - lib/constructorio/configuration.rb
182
+ - lib/constructorio/fields.rb
183
+ - lib/constructorio/helper.rb
184
+ - lib/constructorio/railtie.rb
185
+ - lib/constructorio/tasks/import.rake
186
+ - lib/constructorio/version.rb
187
+ - test/configuration_test.rb
188
+ - test/constructorio_test.rb
189
+ - test/test_helper.rb
190
+ - test/view_helper_test.rb
191
+ homepage: http://constructor.io
192
+ licenses:
193
+ - MIT
194
+ metadata: {}
195
+ post_install_message:
196
+ rdoc_options: []
197
+ require_paths:
198
+ - lib
199
+ required_ruby_version: !ruby/object:Gem::Requirement
200
+ requirements:
201
+ - - ">="
202
+ - !ruby/object:Gem::Version
203
+ version: '0'
204
+ required_rubygems_version: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
209
+ requirements: []
210
+ rubyforge_project:
211
+ rubygems_version: 2.2.2
212
+ signing_key:
213
+ specification_version: 4
214
+ summary: Ruby gem for Constructor.io
215
+ test_files:
216
+ - test/configuration_test.rb
217
+ - test/constructorio_test.rb
218
+ - test/test_helper.rb
219
+ - test/view_helper_test.rb