constructorio 1.0.2 → 1.0.3

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: 40e32ccf33eeef2ae06b3df8d5dabf6502afc172
4
- data.tar.gz: 7f3388a3313802ff44c90bd9134cfdec55b47295
3
+ metadata.gz: 0afa62571df5734cb0bec7f26976b1ff8b4ed039
4
+ data.tar.gz: 8bfbffbaee6ff520ec59a6d5208ef3fd5dba5b7d
5
5
  SHA512:
6
- metadata.gz: 746be9380a15969bf924459873cf6f51818e4ccce284339e32488b049a0f6e0a93562d7c082cbbc8d2dc10a5a05579a6168288e56c08eff93070f2096f0096e9
7
- data.tar.gz: 3d2e4caa400045ee3da00cd9a0271ee42f285ad3e88fd5b40aacfafc494459a2c760f40c8183f030208f6476546d95bc2cb8c1cc940578a016e2f2b17da5f6df
6
+ metadata.gz: 479bdfc0a8a29dfbcb15254af5f36a88438db4763f53d5ccbaa3a67cd5af066ac9f673483b154e36e788b9f47daa4f3e093b36a4dece7e899dd0581804f9db8b
7
+ data.tar.gz: cfeca1527e5c9f1d543e38a514e41e02310c5a181d9e11c29effcbd288d1a68fb8c2a85468317ebf7efe2fcb8778927518c3a99fb893069b600fd3e8d5ab29b6
data/README.md CHANGED
@@ -31,7 +31,7 @@ To add autocomplete to a model:
31
31
 
32
32
  ```
33
33
  class MyModel < ActiveRecord::Base
34
- extend ConstructorIO
34
+ include ConstructorIO
35
35
  autocomplete(['attribute1', 'attribute2'])
36
36
  end
37
37
 
data/lib/constructorio.rb CHANGED
@@ -13,7 +13,10 @@ begin
13
13
  rescue LoadError
14
14
  end
15
15
 
16
+ class MissingItemName < StandardError; end
17
+
16
18
  module ConstructorIO
19
+
17
20
  class << self
18
21
  attr_accessor :configuration
19
22
  end
@@ -26,50 +29,94 @@ module ConstructorIO
26
29
  yield(configuration)
27
30
  end
28
31
 
29
- def autocomplete(fields, autocomplete_key = ConstructorIO.configuration.autocomplete_key)
32
+ # This injects the methods on the included hook
33
+ def self.included base
34
+ base.send :include, InstanceMethods
35
+ base.extend ClassMethods
36
+ end
30
37
 
31
- fields.each do |field|
32
- ConstructorIO::Fields.instance.add(self.model_name, field)
33
- end
38
+ module ClassMethods
39
+ # "fields" is expected to be an array of strings or an array of hashes, like:
40
+ # "product_name", "description"
41
+ # - or -
42
+ # { 'attribute' => 'product_name', 'metadata' => { metadata_one => ->{ something_dynamic }} }
43
+ def autocomplete(fields, autocomplete_key = ConstructorIO.configuration.autocomplete_key)
44
+ # All fields require an attribute
45
+ field_names = fields.map { |f| f.is_a?(String) ? f : f['attribute'] }
46
+ raise MissingItemName if field_names.include? nil
34
47
 
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)
48
+ field_names.each do |field|
49
+ ConstructorIO::Fields.instance.add(self.model_name, field)
39
50
  end
40
- end
41
51
 
42
- before_destroy do |record|
52
+ # transform the data
53
+ transformed = {}
43
54
  fields.each do |field|
44
- record.class.send(:delete_record, record[field.to_sym], autocomplete_key)
55
+ if field.is_a?(String)
56
+ transformed[field] = {}
57
+ else
58
+ transformed[field['attribute']] = field['metadata']
59
+ end
60
+ end
61
+
62
+ after_save do |record|
63
+ updated_fields = record.changed.select { |c| field_names.include? c }
64
+ updated_fields.each do |field|
65
+ record.send(:constructorio_add_record, record[field.to_sym], transformed[field], autocomplete_key)
66
+ end
67
+ end
68
+
69
+ before_destroy do |record|
70
+ field_names.each do |field|
71
+ record.send(:constructorio_delete_record, record[field.to_sym], transformed[field], autocomplete_key)
72
+ end
45
73
  end
46
74
  end
47
75
  end
48
76
 
49
- def add_record(value, autocomplete_key)
50
- call_api("post", value, autocomplete_key)
51
- end
77
+ module InstanceMethods
78
+ def constructorio_add_record(value, metadata = {}, autocomplete_key)
79
+ constructorio_call_api("post", value, metadata, autocomplete_key)
80
+ end
52
81
 
53
- def delete_record(value, autocomplete_key)
54
- call_api("delete", value, autocomplete_key)
55
- end
82
+ def constructorio_delete_record(value, metadata = {}, autocomplete_key)
83
+ constructorio_call_api("delete", value, metadata, autocomplete_key)
84
+ end
85
+
86
+ private
87
+
88
+ def constructorio_make_request_body(value, metadata)
89
+ request_body = { "item_name" => "#{value}" }
90
+ unless metadata.empty?
91
+ metadata.each do |k, v|
92
+ v = instance_exec(&v) if v.is_a? Proc
93
+ request_body[k] = v
94
+ end
95
+ end
96
+ request_body
97
+ end
98
+
99
+ def constructorio_call_api(method, value, metadata, autocomplete_key)
100
+ api_token = ConstructorIO.configuration.api_token
101
+ api_url = ConstructorIO.configuration.api_url || "https://ac.constructor.io/"
102
+ @http_client ||= Faraday.new(url: api_url)
103
+ @http_client.basic_auth(api_token, '')
56
104
 
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}"}|
105
+ request_body = constructorio_make_request_body(value, metadata)
106
+ constructorio_send_request(method, @http_client, request_body, autocomplete_key)
68
107
  end
69
- if response.status.to_s =~ /^2/
70
- return nil
71
- else
72
- return response.status
108
+
109
+ def constructorio_send_request(method, http_client, request_body, autocomplete_key)
110
+ response = http_client.send(method) do |request|
111
+ request.url "/v1/item?autocomplete_key=#{autocomplete_key}"
112
+ request.headers['Content-Type'] = 'application/json'
113
+ request.body = request_body.to_json
114
+ end
115
+ if response.status.to_s =~ /^2/
116
+ return nil
117
+ else
118
+ return response.status
119
+ end
73
120
  end
74
121
  end
75
122
  end
@@ -10,9 +10,9 @@ module ConstructorIO
10
10
  @set = {}
11
11
  end
12
12
 
13
- def add(model, field)
14
- @set[model] ||= {}
15
- @set[model][field] = 1
13
+ def add(model_name, field)
14
+ @set[model_name] ||= {}
15
+ @set[model_name][field] = 1
16
16
  end
17
17
 
18
18
  def list(model_name)
@@ -1,3 +1,3 @@
1
1
  module ConstructorIO
2
- VERSION = "1.0.2"
2
+ VERSION = "1.0.3"
3
3
  end
@@ -1,48 +1,106 @@
1
1
  require_relative 'test_helper'
2
2
 
3
3
  class ConstructorIOTest < MiniTest::Test
4
- def test_add_record
4
+ def test_add_record_makes_request
5
5
  person = Person.new(
6
6
  first_name: "Steven",
7
7
  last_name: "Lai",
8
8
  address: "New York"
9
9
  )
10
- Person.expects(:call_api).with("post", "Steven", "person_autocomplete_key")
11
10
 
11
+ person.stubs(:constructorio_send_request)
12
+
13
+ person.expects(:constructorio_make_request_body)
14
+ assert person.save
15
+ end
16
+
17
+ def test_add_simple_record_makes_request
18
+ person = PersonSimple.new(
19
+ first_name: "Steven",
20
+ last_name: "Lai",
21
+ address: "New York"
22
+ )
23
+
24
+ person.stubs(:constructorio_send_request)
25
+
26
+ person.expects(:constructorio_make_request_body)
27
+ assert person.save
28
+ end
29
+
30
+ def test_add_record_accepts_procs
31
+ person = Person.new(
32
+ first_name: "Steven",
33
+ last_name: "Lai",
34
+ address: "New York"
35
+ )
36
+
37
+ person.expects(:constructorio_send_request).with(
38
+ 'post',
39
+ instance_of(Faraday::Connection),
40
+ {'item_name' => 'Steven', 'test_metadata' => 'test_values', 'test_proc' => 'NEW YORK'},
41
+ 'person_autocomplete_key'
42
+ )
43
+ assert person.save
44
+ end
45
+
46
+ def test_add_simple_record_accepts_procs
47
+ person = PersonSimple.new(
48
+ first_name: "Steven",
49
+ last_name: "Lai",
50
+ address: "New York"
51
+ )
52
+
53
+ person.expects(:constructorio_send_request).with(
54
+ 'post',
55
+ instance_of(Faraday::Connection),
56
+ {'item_name' => 'Steven'},
57
+ 'example_autocomplete_key'
58
+ )
59
+ assert person.save
60
+ end
61
+
62
+ def test_add_record_sends_request
63
+ person = Person.new(
64
+ first_name: "Steven",
65
+ last_name: "Lai",
66
+ address: "New York"
67
+ )
68
+
69
+ person.expects(:constructorio_send_request)
12
70
  assert person.save
13
71
  end
14
72
 
15
- def test_delete_record
16
- Person.expects(:call_api).with("post", "Ronald", "person_autocomplete_key")
73
+ def test_delete_record_makes_request
74
+ Person.any_instance.stubs(:constructorio_call_api)
17
75
  person = Person.create(
18
76
  first_name: "Ronald",
19
77
  last_name: "McDonald",
20
78
  address: "Disneyland"
21
79
  )
22
80
 
23
- Person.expects(:call_api).with("delete", "Ronald", "person_autocomplete_key")
81
+ person.expects(:constructorio_call_api).with("delete", "Ronald", has_entry('test_proc', instance_of(Proc)),"person_autocomplete_key")
24
82
  person.destroy
25
83
  end
26
84
 
27
- def test_add_record_without_key
85
+ def test_add_record_without_key_uses_default_key
28
86
  person = PersonNoKey.new(
29
87
  first_name: "Steven",
30
88
  last_name: "Lai",
31
89
  address: "New York"
32
90
  )
33
91
 
34
- PersonNoKey.expects(:call_api).with("post", "Lai", ConstructorIO.configuration.autocomplete_key)
92
+ person.expects(:constructorio_call_api).with("post", "Lai", anything, ConstructorIO.configuration.autocomplete_key)
35
93
  assert person.save
36
94
  end
37
95
 
38
- def test_fields
39
- Person.expects(:call_api).with("post", "Ronald", "person_autocomplete_key")
96
+ def test_fields_are_tracked
97
+ Person.any_instance.expects(:constructorio_call_api).with("post", "Ronald", anything, "person_autocomplete_key")
40
98
  person = Person.create(
41
99
  first_name: "Ronald",
42
100
  last_name: "McDonald",
43
101
  address: "Disneyland"
44
102
  )
45
103
 
46
- assert_equal ConstructorIO::Fields.instance.list("Person"), ["first_name"]
104
+ assert_equal ConstructorIO::Fields.instance.list('Person'), ["first_name"]
47
105
  end
48
106
  end
data/test/test_helper.rb CHANGED
@@ -24,17 +24,26 @@ ConstructorIO.configure do |config|
24
24
  end
25
25
 
26
26
  class Person < ActiveRecord::Base
27
- extend ConstructorIO
27
+ include ConstructorIO
28
+ autocomplete [{
29
+ 'attribute' => 'first_name',
30
+ 'metadata' => {
31
+ 'test_metadata' => 'test_values',
32
+ 'test_proc' => ->{ self.address.upcase }
33
+ }
34
+ }], "person_autocomplete_key"
35
+ end
28
36
 
29
- autocomplete ['first_name'], "person_autocomplete_key"
37
+ class PersonSimple < ActiveRecord::Base
38
+ self.table_name = 'people'
39
+ include ConstructorIO
40
+ autocomplete [ 'first_name' ]
30
41
  end
31
42
 
32
43
  class PersonNoKey < ActiveRecord::Base
33
44
  self.table_name = 'people'
34
-
35
- extend ConstructorIO
36
-
37
- autocomplete ['last_name']
45
+ include ConstructorIO
46
+ autocomplete [{'attribute' => 'last_name'}]
38
47
  end
39
48
 
40
49
  class FakeView
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: constructorio
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steven Lai
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-08 00:00:00.000000000 Z
11
+ date: 2015-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord