constructorio 1.0.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 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