spigot 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/README.md +25 -32
  4. data/Rakefile +6 -0
  5. data/examples/active_record.rb +18 -15
  6. data/examples/model.rb +38 -7
  7. data/lib/spigot.rb +18 -6
  8. data/lib/spigot/configuration.rb +4 -5
  9. data/lib/spigot/map/base.rb +44 -0
  10. data/lib/spigot/map/definition.rb +69 -0
  11. data/lib/spigot/map/option.rb +27 -0
  12. data/lib/spigot/map/resource.rb +37 -0
  13. data/lib/spigot/map/service.rb +43 -0
  14. data/lib/spigot/patch.rb +1 -1
  15. data/lib/spigot/proxy.rb +3 -2
  16. data/lib/spigot/translator.rb +22 -71
  17. data/lib/spigot/version.rb +1 -1
  18. data/script/console.rb +26 -20
  19. data/spec/fixtures/data/active_user.rb +17 -0
  20. data/spec/fixtures/data/post.rb +15 -0
  21. data/spec/fixtures/data/user.rb +41 -0
  22. data/spec/fixtures/mappings/active_user_map.rb +58 -22
  23. data/spec/fixtures/mappings/post_map.rb +10 -10
  24. data/spec/fixtures/mappings/user_map.rb +73 -29
  25. data/spec/spec_helper.rb +3 -12
  26. data/spec/spigot/active_record_spec.rb +34 -26
  27. data/spec/spigot/base_spec.rb +32 -1
  28. data/spec/spigot/configuration_spec.rb +0 -27
  29. data/spec/spigot/map/base_spec.rb +70 -0
  30. data/spec/spigot/map/definition_spec.rb +45 -0
  31. data/spec/spigot/map/resource_spec.rb +57 -0
  32. data/spec/spigot/map/service_spec.rb +88 -0
  33. data/spec/spigot/translator_spec.rb +110 -113
  34. data/spigot.gemspec +3 -2
  35. metadata +43 -20
  36. data/examples/.DS_Store +0 -0
  37. data/lib/.DS_Store +0 -0
  38. data/lib/spigot/config/.DS_Store +0 -0
  39. data/spec/.DS_Store +0 -0
  40. data/spec/fixtures/.DS_Store +0 -0
  41. data/spec/fixtures/api_data.rb +0 -46
  42. data/spec/spigot/factory_spec.rb +0 -5
@@ -0,0 +1,43 @@
1
+ module Spigot
2
+ module Map
3
+ class Service
4
+
5
+ attr_reader :name
6
+ attr_accessor :resources
7
+
8
+ def initialize(name)
9
+ @name = name.to_s.underscore.to_sym
10
+ @resources = []
11
+ end
12
+
13
+ def self.service(name, &block)
14
+ service = find(name) || Spigot::Map::Service.new(name)
15
+ service.instance_eval(&block) if block_given?
16
+ current_map.update(name, service)
17
+ end
18
+
19
+ def self.find(name)
20
+ current_map.service(name)
21
+ end
22
+
23
+ def resource(name, &block)
24
+ resources << Spigot::Map::Resource.new(name, &block)
25
+ end
26
+
27
+ def reset
28
+ @resources = []
29
+ end
30
+
31
+ def [](name)
32
+ resources.detect{|r| r.instance_variable_get(:@name).to_sym == name.to_sym}
33
+ end
34
+
35
+ private
36
+
37
+ def self.current_map
38
+ Spigot.config.map
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -1,6 +1,6 @@
1
1
  class String
2
2
  # Don't really like patching string here,
3
- # but it's too clean not to.
3
+ # but it's fine for now.
4
4
  def underscore
5
5
  self.gsub(/::/, '/').
6
6
  gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
@@ -14,6 +14,7 @@ module Spigot
14
14
  # @param service [String] This is the service that dictates the proxy.
15
15
  # @param resource [Object] This is the class implementing the proxy.
16
16
  def initialize(service, resource)
17
+ raise MissingServiceError, "No service definition found for #{service}" if Spigot.config.map.service(service).nil?
17
18
  @service = service
18
19
  @resource = resource
19
20
  end
@@ -27,13 +28,13 @@ module Spigot
27
28
  ## #map
28
29
  # Return a hash of the data map the current translator is using
29
30
  def map
30
- translator.mapping.reject{|k,v| k == 'spigot'}
31
+ translator.resource_map
31
32
  end
32
33
 
33
34
  ## #options
34
35
  # Return a hash of any service specific options for this translator. `Spigot.config` not included
35
36
  def options
36
- translator.mapping['spigot'] || {}
37
+ translator.options || {}
37
38
  end
38
39
 
39
40
  end
@@ -12,9 +12,7 @@ module Spigot
12
12
  # in the yaml file for that resource.
13
13
  #
14
14
  # Relevant Configuration:
15
- # config.options_key => The key which the Translator uses to configure a resource mapping.
16
- # config.path => The path which the Translator will look in to find the mappings.
17
- # config.translations => A hash that overrides any mappings found in the `path` directory.
15
+ # config.options_key => The key which the Translator uses to configure a resource_map.
18
16
 
19
17
  attr_reader :service, :resource
20
18
  attr_accessor :data
@@ -35,20 +33,10 @@ module Spigot
35
33
  @data = data || {}
36
34
  end
37
35
 
38
- ## #format(custom_map)
36
+ ## #format
39
37
  # Formats the hash of data passed in to the format specified in the yaml file.
40
- #
41
- # @param custom_map [Hash] Optional hash that you can prefer to use over the correlated translation.
42
- # @param custom_data [Hash] Optional data that you can prefer to use over the @data currently on the object.
43
- def format(custom_map=nil, custom_data=nil)
44
- map = Hashie::Mash.new(custom_map || mapping)
45
- dataset = custom_data || data
46
-
47
- if dataset.is_a?(Array)
48
- dataset.map{|n| translate(map, n) }
49
- elsif dataset.is_a?(Hash)
50
- translate(map, dataset)
51
- end
38
+ def format
39
+ @format ||= data.is_a?(Array) ? data.map{|el| parse(el) } : parse(data)
52
40
  end
53
41
 
54
42
  ## #id
@@ -78,81 +66,44 @@ module Spigot
78
66
  # Default: nil
79
67
  # Array of attributes included in the database query, these are names of columns in your database.
80
68
  def options
81
- @options ||= mapping[Spigot.config.options_key] || {}
69
+ @options ||= resource_map.instance_variable_get(:@options)
82
70
  end
83
71
 
84
72
  def primary_key
85
- options['primary_key'] || "#{service}_id"
73
+ options.primary_key || "#{service}_id"
86
74
  end
87
75
 
88
76
  def foreign_key
89
- options['foreign_key'] || mapping.invert[primary_key] || 'id'
77
+ options.foreign_key || 'id'
90
78
  end
91
79
 
92
80
  def conditions
93
- p_keys = [*(condition_keys.blank? ? primary_key : condition_keys)].map(&:to_s)
94
- keys = mapping.select{|k, v| p_keys.include?(v.to_s) }
95
- format(keys)
81
+ {primary_key => format[primary_key]}
96
82
  end
97
83
 
98
- ## #mapping
99
- # Return a hash of the data map currently being used by this translator, including options.
100
- def mapping
101
- return @mapping if defined?(@mapping)
102
- @mapping = translations[resource_key]
103
- raise MissingResourceError, "There is no #{resource_key} mapping for #{service}" if @mapping.nil?
104
- @mapping
84
+ ## #resource_map
85
+ # Return the mapped resource object for the current service and resource
86
+ def resource_map
87
+ return @resource_map if defined?(@resource_map)
88
+ resource_key = resource.to_s.underscore
89
+ @resource_map = service_map[resource_key]
90
+ raise MissingResourceError, "There is no #{resource_key} resource_map for #{service}" if @resource_map.nil?
91
+ @resource_map
105
92
  end
106
93
 
107
94
  private
108
95
 
109
- def translate(map, dataset)
96
+ def parse(dataset)
110
97
  formatted = {}
111
-
112
- if dataset.is_a?(Array)
113
- return dataset.map{|element| translate(map, element)}
114
- else
115
- dataset.each_pair do |key, val|
116
- next if key == Spigot.config.options_key
117
- attribute = map[key]
118
- next if attribute.nil?
119
-
120
- result = attribute.is_a?(Hash) ? translate(attribute, val) : val
121
- formatted.merge! mergeable_content(key, result, map)
122
- end
98
+ resource_map.definitions.each do |rule|
99
+ result = rule.parse(dataset)
100
+ formatted.merge!(result)
123
101
  end
124
-
125
102
  formatted
126
103
  end
127
104
 
128
- def mergeable_content(key, value, map)
129
- if value.is_a?(Array)
130
- {key.to_s => value}
131
- elsif value.is_a?(Hash)
132
- value
133
- else
134
- {map[key] => value}
135
- end
136
- end
137
-
138
- def condition_keys
139
- options['conditions'].to_s.split(',').map(&:strip)
140
- end
141
-
142
- def resource_key
143
- resource.to_s.underscore
144
- end
145
-
146
- def translations
147
- @translations ||= Hashie::Mash.new(Spigot.config.translations || YAML.load(translation_file))
148
- end
149
-
150
- def translation_file
151
- begin
152
- @translation_file ||= File.read(File.join(Spigot.config.path, "#{service.to_s}.yml"))
153
- rescue Errno::ENOENT => e
154
- raise MissingServiceError, "There is no service map for #{service} defined"
155
- end
105
+ def service_map
106
+ Spigot.config.map ? Spigot.config.map.service(service) : {}
156
107
  end
157
108
 
158
109
  end
@@ -1,3 +1,3 @@
1
1
  module Spigot
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -1,6 +1,32 @@
1
1
  require 'active_record'
2
2
  require 'spigot'
3
3
 
4
+ Spigot.define do
5
+ service :github do
6
+ resource :active_user do
7
+ id :github_id
8
+ full_name :name
9
+ login :username
10
+ contact do
11
+ address :address
12
+ telephone do
13
+ work :work_phone
14
+ home :home_phone
15
+ end
16
+ url :homepage do |value|
17
+ "https://github.com/#{value}"
18
+ end
19
+ end
20
+ end
21
+
22
+ resource :pull_request do
23
+ id :id
24
+ title :title
25
+ body :body
26
+ end
27
+ end
28
+ end
29
+
4
30
  ActiveRecord::Base.logger = Spigot.logger
5
31
  require File.join(Spigot.root, 'spec', 'support', 'active_record')
6
32
 
@@ -8,24 +34,4 @@ class ActiveUser < ActiveRecord::Base
8
34
  include Spigot::Base
9
35
  end
10
36
 
11
- map = {'activeuser' => {
12
- 'name' => 'name',
13
- 'username' => 'login',
14
- 'spigot' => {
15
- 'primary_key' => 'username'
16
- }
17
- }}
18
-
19
- conditions = {'activeuser' => {
20
- 'name' => 'name',
21
- 'login' => 'username',
22
- 'spigot' => {
23
- 'primary_key' => 'username'
24
- }
25
- }}
26
-
27
- Spigot.configure do |config|
28
- config.translations = conditions
29
- end
30
-
31
37
  user = ActiveUser.create(name: 'Matt', username: 'mttwrnr', token: 'abc123')
@@ -0,0 +1,17 @@
1
+ module Spigot
2
+ module Data
3
+ class ActiveUser
4
+ class << self
5
+
6
+ def basic
7
+ {full_name: 'Dean Martin', login: 'classyasfuck', auth_token: '123abc'}
8
+ end
9
+
10
+ def alt
11
+ {full_name: 'Frank Sinatra', login: 'livetilidie', auth_token: '987zyx'}
12
+ end
13
+
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ module Spigot
2
+ module Data
3
+ class Post
4
+ class << self
5
+ def basic
6
+ {'title' => 'Brief Article', 'body' => 'lorem ipsum'}
7
+ end
8
+
9
+ def alt
10
+ {'title' => 'Regular Article', 'body' => 'dolor sit amet', 'author' => 'Dean Martin'}
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,41 @@
1
+ module Spigot
2
+ module Data
3
+ class User
4
+ class << self
5
+ def basic
6
+ {'id' => '123', 'full_name' => 'Dean Martin', 'login' => 'classyasfuck'}
7
+ end
8
+
9
+ def alt
10
+ {'full_name' => 'Frank Sinatra', 'login' => 'livetilidie', 'auth_token' => '456bcd'}
11
+ end
12
+
13
+ def full
14
+ basic.merge('auth_token' => '123abc')
15
+ end
16
+
17
+ def array
18
+ [full, alt]
19
+ end
20
+
21
+ def nested_array
22
+ {'account' => 'Rockafella', 'users' => array, 'count' => 2}
23
+ end
24
+
25
+ def nested
26
+ full.merge('login' => login_info)
27
+ end
28
+
29
+ def double_nested
30
+ full.merge('login' => {'contact' => login_info, 'last_seen_ip' => '127.0.0.1'})
31
+ end
32
+
33
+ private
34
+
35
+ def login_info
36
+ {'email' => 'dino@amore.io', 'user_name' => 'classyasfuck'}
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,42 +1,78 @@
1
1
  module Spigot
2
2
  module Mapping
3
-
4
3
  class ActiveUser
5
4
 
6
- def self.basic
7
- {'active_user' => base}
5
+ def self.stub
6
+ template do
7
+ login :username
8
+ full_name :name
9
+ end
8
10
  end
9
11
 
10
12
  def self.with_options
11
- {'active_user' => base.merge('spigot' => options)}
12
- end
13
-
14
- def self.non_unique_key
15
- {'active_user' => base.merge('auth_token' => 'token', 'spigot' => non_unique)}
13
+ template do
14
+ login :username
15
+ full_name :name
16
+ options do
17
+ primary_key :username
18
+ foreign_key :login
19
+ end
20
+ end
16
21
  end
17
22
 
18
- def self.with_invalid_options
19
- {'active_user' => base.merge('spigot' => invalid_options)}
23
+ def self.non_unique_keys
24
+ template do
25
+ login :username
26
+ full_name :name
27
+ auth_token :token
28
+ options do
29
+ primary_key :token
30
+ foreign_key :auth_token
31
+ end
32
+ end
20
33
  end
21
34
 
22
35
  private
23
36
 
24
- def self.base
25
- {'full_name' => 'name', 'login' => 'username'}
37
+ def self.template(&block)
38
+ Spigot.define do
39
+ service :github do
40
+ resource :active_user do
41
+ self.instance_eval(&block)
42
+ end
43
+ end
44
+ end
26
45
  end
27
46
 
28
- def self.options
29
- {'primary_key' => 'username', 'foreign_key' => 'login'}
30
- end
47
+ # def self.basic
48
+ # {'active_user' => base}
49
+ # end
31
50
 
32
- def self.non_unique
33
- {'primary_key' => 'token', 'foreign_key' => 'auth_token'}
34
- end
51
+ # def self.non_unique_key
52
+ # {'active_user' => base.merge('auth_token' => 'token', 'spigot' => non_unique)}
53
+ # end
35
54
 
36
- def self.invalid_options
37
- {'primary_key' => 'nosuchcolumn', 'foreign_key' => 'nosuchkey'}
38
- end
39
- end
55
+ # def self.with_invalid_options
56
+ # {'active_user' => base.merge('spigot' => invalid_options)}
57
+ # end
58
+
59
+ # private
60
+
61
+ # def self.base
62
+ # {'full_name' => 'name', 'login' => 'username'}
63
+ # end
40
64
 
65
+ # def self.options
66
+ # {'primary_key' => 'username', 'foreign_key' => 'login'}
67
+ # end
68
+
69
+ # def self.non_unique
70
+ # {'primary_key' => 'token', 'foreign_key' => 'auth_token'}
71
+ # end
72
+
73
+ # def self.invalid_options
74
+ # {'primary_key' => 'nosuchcolumn', 'foreign_key' => 'nosuchkey'}
75
+ # end
76
+ end
41
77
  end
42
78
  end