ensconce 0.0.2

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.
Files changed (34) hide show
  1. checksums.yaml +15 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +69 -0
  4. data/Rakefile +9 -0
  5. data/lib/ensconce.rb +10 -0
  6. data/lib/ensconce/adapters/adapter.rb +52 -0
  7. data/lib/ensconce/adapters/mydex_adapter.rb +75 -0
  8. data/lib/ensconce/adapters/yaml_file_adapter.rb +21 -0
  9. data/lib/ensconce/data_store.rb +41 -0
  10. data/lib/ensconce/hash_builder.rb +72 -0
  11. data/lib/ensconce/key_mappers/key_map.rb +35 -0
  12. data/lib/ensconce/key_mappers/mydex_key_map.rb +23 -0
  13. data/lib/ensconce/mangle.rb +31 -0
  14. data/lib/ensconce/version.rb +15 -0
  15. data/test/data/users.yml +9 -0
  16. data/test/ensconce/adapters/adapter_test.rb +22 -0
  17. data/test/ensconce/adapters/mydex_adapter_test.rb +49 -0
  18. data/test/ensconce/adapters/yaml_file_adapter_test.rb +31 -0
  19. data/test/ensconce/data_store_test.rb +72 -0
  20. data/test/ensconce/key_mappers/hash_builder_test.rb +102 -0
  21. data/test/ensconce/key_mappers/mydex_key_map_test.rb +20 -0
  22. data/test/ensconce/mangle_test.rb +25 -0
  23. data/test/fixtures/users.yml +9 -0
  24. data/test/fixtures/vcr_cassettes/datastore_after_mydex_adapter_test.yml +44 -0
  25. data/test/fixtures/vcr_cassettes/datastore_before_mydex_adapter_test.yml +85 -0
  26. data/test/fixtures/vcr_cassettes/datastore_get_Harry.yml +44 -0
  27. data/test/fixtures/vcr_cassettes/datastore_get_Mary.yml +44 -0
  28. data/test/fixtures/vcr_cassettes/datastore_get_Trevor.yml +44 -0
  29. data/test/fixtures/vcr_cassettes/datastore_push_Harry.yml +44 -0
  30. data/test/fixtures/vcr_cassettes/datastore_push_Mary.yml +44 -0
  31. data/test/fixtures/vcr_cassettes/datastore_push_Trevor.yml +44 -0
  32. data/test/fixtures/vcr_cassettes/datastore_test_get.yml +44 -0
  33. data/test/test_helper.rb +67 -0
  34. metadata +110 -0
@@ -0,0 +1,31 @@
1
+
2
+ module Ensconce
3
+ module Mangle
4
+
5
+ # Hash#merge will replace the value of a key with its replacement's value.
6
+ # If the value is itself a hash, the original is replaced.
7
+ # With deep_merge, if the value is a hash the original value is merged with
8
+ # the replacements.
9
+ # original = {one: {two: 2}, three: 3}
10
+ # replacement = {one: {four: 4}}
11
+ # original.merge(replacement) --> {one: {four: 4}, three: 3}
12
+ # Mangle.deep_merge(original, replacement) --> {one: {two: 2, four: 4}, three: 3}
13
+ def self.deep_merge(original, replacement)
14
+ if original.kind_of? Hash
15
+ original.merge(replacement){|key, oldval, newval| deep_merge(oldval, newval)}
16
+ else
17
+ replacement
18
+ end
19
+ end
20
+
21
+ # Changes the keys of a hash based on a hash. The map is a hash where the
22
+ # values are the old keys, and the values are the replacement keys
23
+ # original = {one: {two: 2}, three: 3}
24
+ # hash = {one: :four, three: :five}
25
+ # Mangle.rekey(original, hash) --> {four: {two: 2}, five: 3}
26
+ def self.rekey(hash, change_map)
27
+ change_map.each{|old, new| hash[new] = hash.delete(old)}
28
+ return hash
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,15 @@
1
+ module Ensconce
2
+ VERSION = "0.0.2"
3
+ end
4
+
5
+ # History
6
+ # =======
7
+ #
8
+ # 0.0.2: Cleansed release
9
+ # -----------------------
10
+ # Re-release with settings.yml purged
11
+ #
12
+ # 0.0.1: First release
13
+ # --------------------
14
+ # Includes YAML and MyDex adapters.
15
+ #
@@ -0,0 +1,9 @@
1
+ user_1:
2
+ first_name: Bob
3
+ last_name: Bloggs
4
+ gender: Male
5
+
6
+ user_2:
7
+ first_name: Jane
8
+ last_name: Doe
9
+ gender: Female
@@ -0,0 +1,22 @@
1
+ require 'test/unit'
2
+ require_relative '../../../lib/ensconce'
3
+
4
+ module Ensconce
5
+ class AdapterTest < Test::Unit::TestCase
6
+ def test_config
7
+ stuff = {foo: 'bar'}
8
+ Adapter.config(stuff)
9
+ assert_equal(stuff, Adapter.options)
10
+ end
11
+
12
+ def test_method_holders
13
+ methods = %w{get push}
14
+ adapter = Adapter.new
15
+ methods.each do |method|
16
+ assert_raise RuntimeError, "Adapter.#{method} should raise an error." do
17
+ adapter.send method
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,49 @@
1
+ require_relative '../../test_helper'
2
+
3
+ module Ensconce
4
+ class MydexAdapterTest < Test::Unit::TestCase
5
+ def setup
6
+
7
+ MydexAdapter.config(
8
+ url: settings['mydex']['url'],
9
+ api_key: settings['mydex']['api_key']
10
+ )
11
+ end
12
+
13
+ def test_adapter_for
14
+ user = TestUser.new(
15
+ :key => settings['mydex']['key'],
16
+ :con_id => settings['mydex']['con_id'],
17
+ :id => settings['mydex']['id']
18
+ )
19
+ @adapter = MydexAdapter.for(user, :data_set => 'field_ds_personal_details')
20
+ assert_equal(settings['mydex']['key'], @adapter.settings.key)
21
+ end
22
+
23
+
24
+
25
+ def test_get
26
+ test_adapter_for
27
+ VCR.use_cassette('datastore_test_get') do
28
+ data = @adapter.get
29
+ assert_equal(MydexKeyMap.field_ds_personal_details_map[:replacement], data.keys)
30
+ assert(data.values.collect{|v| v unless v.empty?}.compact.length > 0, "Values should not all be empty")
31
+ end
32
+ end
33
+
34
+ def test_push
35
+ values = %w{Harry Mary Trevor}
36
+ key = 'first_name'
37
+ test_adapter_for
38
+ values.each do |value|
39
+ VCR.use_cassette("datastore_push_#{value}") do
40
+ @adapter.push({key => value})
41
+ end
42
+ VCR.use_cassette("datastore_get_#{value}") do
43
+ result = @adapter.get
44
+ assert_equal(value, result[key])
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,31 @@
1
+ require_relative '../../test_helper'
2
+
3
+ module Ensconce
4
+ class YamlFileAdapterTest < Test::Unit::TestCase
5
+
6
+ def setup
7
+ @users = fixture['users']
8
+ YamlFileAdapter.config(
9
+ :file => data_path('users')
10
+ )
11
+ @user = TestUser.new(:id => 'user_1')
12
+ @adapter = YamlFileAdapter.for(@user)
13
+ end
14
+
15
+ def test_setup
16
+ assert_equal(current_data_for('users'), @users)
17
+ end
18
+
19
+ def test_get
20
+ assert_equal(@users[@user.id], @adapter.get)
21
+ end
22
+
23
+ def test_push
24
+ update = {"first_name" => 'Harry'}
25
+ @adapter.push(update)
26
+ @users[@user.id].merge!(update)
27
+ assert_equal(@users, current_data_for('users'))
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,72 @@
1
+ require_relative '../test_helper'
2
+
3
+ module Ensconce
4
+ class DataStoreTest < Test::Unit::TestCase
5
+ def setup
6
+ DataStore.adapter = YamlFileAdapter.config(:file => data_path('users'))
7
+ @users = fixture['users']
8
+ user = TestUser.new(id: 'user_1')
9
+ @data_store = DataStore.open user
10
+ end
11
+
12
+ def test_open
13
+ assert_equal(@users['user_1'], @data_store)
14
+ end
15
+
16
+ def test_save
17
+ name = 'Gillian'
18
+ @data_store['first_name'] = name
19
+ @data_store.save
20
+ @users['user_1'].merge!({'first_name' => name})
21
+ assert_equal(@users, current_data_for('users'))
22
+ end
23
+
24
+ def test_new
25
+ user = TestUser.new(id: 'user_99')
26
+ @user = {
27
+ user.id => {
28
+ 'first_name' => 'Ice',
29
+ 'last_name' => 'Cream',
30
+ 'gender' => 'female'
31
+ }
32
+ }
33
+ @data_store = DataStore.new(user, :data => @user[user.id])
34
+ assert_equal(@user[user.id], @data_store)
35
+ end
36
+
37
+ def test_create
38
+ test_new
39
+ @data_store.save
40
+ @users.merge! @user
41
+ assert_equal(@users, current_data_for('users'))
42
+ end
43
+
44
+ def test_with_mydex_adapter
45
+ DataStore.adapter = MydexAdapter.config(
46
+ url: settings['mydex']['url'],
47
+ api_key: settings['mydex']['api_key']
48
+ )
49
+ @user = TestUser.new(
50
+ :key => settings['mydex']['key'],
51
+ :con_id => settings['mydex']['con_id'],
52
+ :id => settings['mydex']['id']
53
+ )
54
+ VCR.use_cassette('datastore_before_mydex_adapter_test') do
55
+ @data_store = DataStore.open(
56
+ @user,
57
+ :data_set => 'field_ds_personal_details')
58
+ @name = 'Gillian'
59
+ @data_store['first_name'] = @name
60
+ @data_store.save
61
+ end
62
+ VCR.use_cassette('datastore_after_mydex_adapter_test') do
63
+ result = DataStore.open(
64
+ @user,
65
+ :data_set => 'field_ds_personal_details'
66
+ )
67
+ assert_equal(@name, result['first_name'])
68
+ end
69
+
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,102 @@
1
+ require_relative '../../test_helper'
2
+
3
+ module Ensconce
4
+ class HashBuilderTest < Test::Unit::TestCase
5
+
6
+ def setup
7
+ @words = %w{one two three}
8
+ @numbers = %w{1 2 3}
9
+ @hash_builder = HashBuilder.new(
10
+ :keys => @words,
11
+ :values => @numbers
12
+ )
13
+ end
14
+
15
+ def test_initiation
16
+ assert_equal @words, @hash_builder.keys
17
+ assert_equal @numbers, @hash_builder.values
18
+ end
19
+
20
+ def test_lack_of_keys
21
+ hash_builder = HashBuilder.new(:values => @numbers)
22
+ assert_raise RuntimeError do
23
+ hash_builder.hash
24
+ end
25
+ end
26
+
27
+ def test_lack_of_values
28
+ hash_builder = HashBuilder.new(:keys => @numbers)
29
+ assert_raise RuntimeError do
30
+ hash_builder.hash
31
+ end
32
+ end
33
+
34
+ def test_map
35
+ expected = {'one' => '1', 'two' => '2', 'three' => '3'}
36
+ assert_equal(expected, @hash_builder.hash)
37
+ end
38
+
39
+ def test_keys_mod
40
+ @hash_builder.keys_mod = lambda {|element| element.upcase}
41
+ expected = {'ONE' => '1', 'TWO' => '2', 'THREE' => '3'}
42
+ assert_equal(expected, @hash_builder.hash)
43
+ end
44
+
45
+ def test_keys_mod_with_invalid_input
46
+ @hash_builder.keys_mod = 'x'
47
+ assert_raise RuntimeError do
48
+ @hash_builder.hash
49
+ end
50
+ end
51
+
52
+ def test_values_mod
53
+ @hash_builder.values_mod = lambda {|element| (element.to_i * 2).to_s}
54
+ expected = {'one' => '2', 'two' => '4', 'three' => '6'}
55
+ assert_equal(expected, @hash_builder.hash)
56
+ end
57
+
58
+ # Test added to show how procs with returns in mods can cause unexpected results
59
+ def test_mod_with_proc
60
+ @hash_builder.values_mod = Proc.new {|element| return (element.to_i * 2).to_s}
61
+ map = @hash_builder.hash
62
+ flunk "Never gets here"
63
+ # because return in Proc stops process and returns value to test_mod_with_proc caller
64
+ end
65
+
66
+ # Demonstration that it is the return in the Proc that messes up the test.
67
+ # If you alter 'expected' in this test, the test will fail.
68
+ def test_mod_with_proc_and_no_return
69
+ @hash_builder.values_mod = Proc.new {|element| (element.to_i * 2).to_s}
70
+ expected = {'one' => '2', 'two' => '4', 'three' => '6'}
71
+ map = @hash_builder.hash
72
+ assert_equal(expected, map)
73
+ end
74
+
75
+ # Test with lambda shows a more predictable result
76
+ def test_mod_with_lambda
77
+ @hash_builder.values_mod = lambda {|element| return (element.to_i * 2).to_s}
78
+ expected = {'one' => '2', 'two' => '4', 'three' => '6'}
79
+ map = @hash_builder.hash
80
+ assert_equal(expected, map)
81
+ end
82
+
83
+ def test_mod_with_lambda_and_no_return
84
+ @hash_builder.values_mod = lambda {|element| (element.to_i * 2).to_s}
85
+ expected = {'one' => '2', 'two' => '4', 'three' => '6'}
86
+ map = @hash_builder.hash
87
+ assert_equal(expected, map)
88
+ end
89
+
90
+ def test_mods_on_initiation
91
+ hash_builder = HashBuilder.new(
92
+ :keys => @words,
93
+ :values => @numbers,
94
+ :keys_mod => lambda {|element| element.reverse},
95
+ :values_mod => Proc.new {|element| (element.to_i + 2).to_s}
96
+ )
97
+ expected = {'eno' => '3', 'owt' => '4', 'eerht' => '5'}
98
+ assert_equal(expected, hash_builder.hash)
99
+ end
100
+
101
+ end
102
+ end
@@ -0,0 +1,20 @@
1
+ require_relative '../../test_helper'
2
+
3
+ module Ensconce
4
+ class MydexKeyMapTest < Test::Unit::TestCase
5
+ def test_for
6
+ expected = {
7
+ "field_personal_fname"=>"first_name",
8
+ "field_personal_faname"=>"last_name",
9
+ "field_personal_gender"=>"gender",
10
+ "field_personal_maname"=>"maiden_name",
11
+ "field_personal_mname"=>"middle_name",
12
+ "field_personal_nickname"=>"nick_name",
13
+ "field_personal_suffix"=>"suffix",
14
+ "field_personal_title"=>"title"
15
+ }
16
+ map = MydexKeyMap.for('field_ds_personal_details')
17
+ assert_equal(expected, map)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,25 @@
1
+ require_relative '../test_helper'
2
+
3
+ module Ensconce
4
+ class MangleTest < Test::Unit::TestCase
5
+
6
+ def setup
7
+ @hash = {foo: {bar: 38, chew: 12}, this: 'that'}
8
+ end
9
+
10
+ def test_deep_merge
11
+ replacement = {foo: {bar: 21}}
12
+ expected = {foo: {bar: 21, chew: 12}, this: 'that'}
13
+ assert_equal(expected, Mangle.deep_merge(@hash, replacement))
14
+ end
15
+
16
+ def test_rekey
17
+ map = {
18
+ foo: :changed_foo,
19
+ this: :changed_this
20
+ }
21
+ expected = {changed_foo: {bar: 38, chew: 12}, changed_this: 'that'}
22
+ assert_equal(expected, Mangle.rekey(@hash, map))
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,9 @@
1
+ user_1:
2
+ first_name: Bob
3
+ last_name: Bloggs
4
+ gender: Male
5
+
6
+ user_2:
7
+ first_name: Jane
8
+ last_name: Doe
9
+ gender: Female
@@ -0,0 +1,44 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://sbx-api.mydex.org/api/pds/pds/93.json?api_key=rN31O75AWviNYezE2vWsMDP6kS88Zc5P&con_id=93-1545&data_set=field_ds_personal_details&dataset=field_ds_personal_details&key=LlPwdnq38tMtCPP7u60HjTYy35MxAVkf&source_type=connection
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ User-Agent:
11
+ - Faraday v0.8.6
12
+ Accept-Encoding:
13
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
14
+ Accept:
15
+ - ! '*/*'
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Server:
22
+ - nginx
23
+ Date:
24
+ - Mon, 17 Mar 2014 14:20:21 GMT
25
+ Content-Type:
26
+ - application/json
27
+ Transfer-Encoding:
28
+ - chunked
29
+ Connection:
30
+ - keep-alive
31
+ Expires:
32
+ - Sun, 19 Nov 1978 05:00:00 GMT
33
+ Last-Modified:
34
+ - Mon, 17 Mar 2014 14:20:21 +0000
35
+ Cache-Control:
36
+ - no-cache, must-revalidate, post-check=0, pre-check=0
37
+ Etag:
38
+ - ! '"1395066021"'
39
+ body:
40
+ encoding: US-ASCII
41
+ string: ! '{"field_ds_personal_details":{"instance_0":{"field_personal_faname":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_fname":{"value":"Gillian","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_gender":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_maname":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_mname":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_nickname":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_suffix":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_title":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}}}}}'
42
+ http_version:
43
+ recorded_at: Mon, 17 Mar 2014 14:20:27 GMT
44
+ recorded_with: VCR 2.4.0
@@ -0,0 +1,85 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://sbx-api.mydex.org/api/pds/pds/93.json?api_key=rN31O75AWviNYezE2vWsMDP6kS88Zc5P&con_id=93-1545&data_set=field_ds_personal_details&dataset=field_ds_personal_details&key=LlPwdnq38tMtCPP7u60HjTYy35MxAVkf&source_type=connection
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ User-Agent:
11
+ - Faraday v0.8.6
12
+ Accept-Encoding:
13
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
14
+ Accept:
15
+ - ! '*/*'
16
+ response:
17
+ status:
18
+ code: 200
19
+ message: OK
20
+ headers:
21
+ Server:
22
+ - nginx
23
+ Date:
24
+ - Mon, 17 Mar 2014 14:20:20 GMT
25
+ Content-Type:
26
+ - application/json
27
+ Transfer-Encoding:
28
+ - chunked
29
+ Connection:
30
+ - keep-alive
31
+ Expires:
32
+ - Sun, 19 Nov 1978 05:00:00 GMT
33
+ Last-Modified:
34
+ - Mon, 17 Mar 2014 14:20:20 +0000
35
+ Cache-Control:
36
+ - no-cache, must-revalidate, post-check=0, pre-check=0
37
+ Etag:
38
+ - ! '"1395066020"'
39
+ body:
40
+ encoding: US-ASCII
41
+ string: ! '{"field_ds_personal_details":{"instance_0":{"field_personal_faname":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_fname":{"value":"Trevor","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_gender":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_maname":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_mname":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_nickname":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_suffix":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}},"field_personal_title":{"value":"","access":{"r":{"a":"1","s":"A"},"w":{"a":"1","s":"A"}}}}}}'
42
+ http_version:
43
+ recorded_at: Mon, 17 Mar 2014 14:20:26 GMT
44
+ - request:
45
+ method: put
46
+ uri: https://sbx-api.mydex.org/api/pds/pds/93.json?api_key=rN31O75AWviNYezE2vWsMDP6kS88Zc5P&con_id=93-1545&data_set=field_ds_personal_details&key=LlPwdnq38tMtCPP7u60HjTYy35MxAVkf&source_type=connection
47
+ body:
48
+ encoding: UTF-8
49
+ string: ! '{"field_ds_personal_details":[{"field_personal_fname":"Gillian","field_personal_faname":"","field_personal_gender":"","field_personal_maname":"","field_personal_mname":"","field_personal_nickname":"","field_personal_suffix":"","field_personal_title":""}]}'
50
+ headers:
51
+ User-Agent:
52
+ - Faraday v0.8.6
53
+ Content-Type:
54
+ - application/json
55
+ Accept:
56
+ - ! '*/*'
57
+ response:
58
+ status:
59
+ code: 200
60
+ message: OK
61
+ headers:
62
+ Server:
63
+ - nginx
64
+ Date:
65
+ - Mon, 17 Mar 2014 14:20:21 GMT
66
+ Content-Type:
67
+ - application/json
68
+ Transfer-Encoding:
69
+ - chunked
70
+ Connection:
71
+ - keep-alive
72
+ Expires:
73
+ - Sun, 19 Nov 1978 05:00:00 GMT
74
+ Last-Modified:
75
+ - Mon, 17 Mar 2014 14:20:21 +0000
76
+ Cache-Control:
77
+ - no-cache, must-revalidate, post-check=0, pre-check=0
78
+ Etag:
79
+ - ! '"1395066021"'
80
+ body:
81
+ encoding: US-ASCII
82
+ string: ! '{"success":1,"data":{"field_ds_personal_details":[{"field_personal_fname":"Gillian","field_personal_faname":"","field_personal_gender":"","field_personal_maname":"","field_personal_mname":"","field_personal_nickname":"","field_personal_suffix":"","field_personal_title":""}]}}'
83
+ http_version:
84
+ recorded_at: Mon, 17 Mar 2014 14:20:26 GMT
85
+ recorded_with: VCR 2.4.0