boblail-unfuddle 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6c4a223f7cf345cfab592d4b71aa877cb04bbbe7
4
+ data.tar.gz: fb9e1a041a454022f5c779743ef5c6df879f7fd9
5
+ SHA512:
6
+ metadata.gz: 7c0da95ccb04a123c6553cfe44a488c8a8f562aa954a79ec0f26277f6ed549a48e2072d49fbbe3f28a33ffd4eb6029892f247e8d8e808d849dc36ce22b1339b7
7
+ data.tar.gz: 7810194c1b509809f2031c3ba061978936e56d8f2e30483ab56b444e28e2d4ecda9b7697d39bcd248bcad4fda8f924a3301adf1033fb69d18771b89c3aa1dab6
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in hiccup.gemspec
4
+ gemspec
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "lib"
6
+ t.libs << "test"
7
+ t.pattern = "test/**/*_test.rb"
8
+ t.verbose = false
9
+ end
@@ -0,0 +1,171 @@
1
+ require 'faraday'
2
+ require 'json'
3
+ require 'active_support/core_ext/benchmark'
4
+ require 'active_support/core_ext/hash'
5
+ require 'active_support/core_ext/hash/indifferent_access'
6
+ require 'unfuddle/configuration'
7
+ require 'unfuddle/error'
8
+ require 'unfuddle/project'
9
+ require 'unfuddle/person'
10
+ require 'unfuddle/response'
11
+ require 'unfuddle/has_tickets'
12
+
13
+
14
+ class Unfuddle
15
+ include HasTickets
16
+
17
+ class << self
18
+
19
+ def config(options=nil)
20
+ configuration = Unfuddle::Configuration.new
21
+ configuration.from_options(options) if options
22
+ yield configuration if block_given?
23
+ instance.configuration = configuration
24
+ end
25
+
26
+ def with_config(options)
27
+ current_configuration = instance.configuration
28
+ begin
29
+ config(current_configuration.merge(options))
30
+ yield
31
+ ensure
32
+ instance.configuration = current_configuration
33
+ end
34
+ end
35
+
36
+ def instance
37
+ @unfuddle ||= self.new
38
+ end
39
+
40
+ def assert_response!(expected_response_code, response)
41
+ unless response.status == expected_response_code
42
+ raise InvalidResponseError.new(response)
43
+ end
44
+ end
45
+
46
+ # Homemade `delegate`
47
+ [:get, :post, :put, :delete, :configuration].each do |method|
48
+ module_eval <<-RUBY
49
+ def #{method}(*args, &block)
50
+ instance.#{method}(*args, &block)
51
+ end
52
+ RUBY
53
+ end
54
+
55
+ [:subdomain, :username, :password, :logger, :include_associations?, :include_closed_on?, :timeout].each do |method|
56
+ module_eval <<-RUBY
57
+ def #{method}
58
+ configuration.#{method}
59
+ end
60
+ RUBY
61
+ end
62
+
63
+ end
64
+
65
+ attr_reader :configuration
66
+
67
+ def configuration=(configuration)
68
+ @configuration = configuration
69
+ @http = nil
70
+ end
71
+
72
+ [:subdomain, :username, :password, :logger, :include_associations?, :include_closed_on?, :timeout].each do |method|
73
+ module_eval <<-RUBY
74
+ def #{method}
75
+ configuration.#{method}
76
+ end
77
+ RUBY
78
+ end
79
+
80
+
81
+
82
+ def projects
83
+ Unfuddle.Project.all
84
+ end
85
+
86
+ def project(project_id)
87
+ Unfuddle::Project.new("id" => project_id)
88
+ end
89
+
90
+ def people(options={})
91
+ Unfuddle::Person.all(options)
92
+ end
93
+
94
+ def person(person_id)
95
+ Unfuddle::Person.new("id" => person_id)
96
+ end
97
+
98
+
99
+
100
+ def get(path)
101
+ http_send_with_logging :get, path
102
+ end
103
+
104
+ def post(path, object)
105
+ http_send_with_logging :post, path, object.to_xml
106
+ end
107
+
108
+ def put(path, object)
109
+ http_send_with_logging :put, path, object.to_xml
110
+ end
111
+
112
+ def delete(path)
113
+ http_send_with_logging :delete, path
114
+ end
115
+
116
+
117
+
118
+ def configured?
119
+ subdomain && username && password
120
+ end
121
+
122
+
123
+
124
+ protected
125
+
126
+ def http_send_with_logging(method, path, body=nil, headers={})
127
+ path = "/api/v1/#{path}"
128
+ headers = headers.merge({ # read JSON, write XML
129
+ "Accept" => "application/json",
130
+ "Content-type" => "application/xml" })
131
+
132
+ response = nil
133
+ ms = Benchmark.ms do
134
+ response = http_send(method, path, body, headers)
135
+ end
136
+ response
137
+ ensure
138
+ message = "[unfuddle:#{method}] #{path}"
139
+ message << "\n #{body}" if body
140
+ message = '%s (%.1fms)' % [ message, ms ] if ms
141
+ logger.info(message)
142
+
143
+ url = http.url_prefix.to_s + path
144
+ logger.warn "[unfuddle:#{method}] URL length exceeded 2000 characters" if url.length > 2000
145
+ end
146
+
147
+ def http_send(method, path, body, headers)
148
+ response = http.public_send(method, path, body, headers) do |req|
149
+ req.options[:timeout] = timeout
150
+ end
151
+
152
+ Response.new(response).tap do |response|
153
+ raise ServerError.new(response) if response.server_error?
154
+ raise UnauthorizedError.new(response) if response.unauthorized?
155
+ end
156
+
157
+ rescue Faraday::Error::ConnectionFailed
158
+ raise ConnectionError, $!.message
159
+ rescue Faraday::Error::TimeoutError, Errno::ETIMEDOUT
160
+ raise TimeoutError, $!.message
161
+ end
162
+
163
+ def http
164
+ raise ConfigurationError, "Unfuddle is not configured" unless configured?
165
+ @http ||= Faraday.new("https://#{subdomain}.unfuddle.com", ssl: {verify: false}) do |faraday|
166
+ faraday.adapter Faraday.default_adapter
167
+ faraday.basic_auth username, password
168
+ end
169
+ end
170
+
171
+ end
@@ -0,0 +1,223 @@
1
+ require 'unfuddle'
2
+ require 'active_support/inflector'
3
+ require 'active_support/core_ext/hash'
4
+
5
+
6
+ class Unfuddle
7
+ class Base
8
+
9
+ def initialize(attributes)
10
+ __set_attributes(attributes)
11
+ end
12
+
13
+ def unfetched?
14
+ @attributes.keys == %w{id}
15
+ end
16
+
17
+ def id
18
+ @attributes["id"]
19
+ end
20
+
21
+ def __set_attributes(attributes)
22
+ raise ArgumentError, "attributes is expected to be a hash, but it was #{attributes.class} instead" unless attributes.is_a?(Hash)
23
+ if @attributes
24
+ @attributes.merge! attributes
25
+ else
26
+ @attributes = attributes
27
+ end
28
+ end
29
+
30
+
31
+
32
+ # Respond to attributes
33
+
34
+ def attributes
35
+ _attributes.dup
36
+ end
37
+
38
+ def method_missing(method_name, *args, &block)
39
+ if has_attribute?(method_name)
40
+ _attributes[method_name.to_s]
41
+ else
42
+ super(method_name, *args, &block)
43
+ end
44
+ end
45
+
46
+ def respond_to?(method_name)
47
+ super(method_name) || has_attribute?(method_name)
48
+ end
49
+
50
+ def has_attribute?(attribute_name)
51
+ _attributes.key?(attribute_name.to_s)
52
+ end
53
+
54
+ def write_attribute(attribute, value)
55
+ _attributes[attribute.to_s] = value
56
+ end
57
+
58
+ def update_attributes!(attributes)
59
+ attributes.each do |key, value|
60
+ write_attribute(key, value)
61
+ end
62
+ save!
63
+ end
64
+
65
+ def update_attribute(attribute, value)
66
+ write_attribute(attribute, value)
67
+ save!
68
+ end
69
+
70
+
71
+
72
+ # Finders
73
+
74
+ class << self
75
+
76
+ def find_by(*attributes)
77
+ attributes.each do |attribute|
78
+ instance_eval <<-RUBY
79
+ def find_by_#{attribute}(value)
80
+ all.find { |instance| instance.#{attribute} == value }
81
+ end
82
+ RUBY
83
+ end
84
+ end
85
+
86
+ end
87
+
88
+
89
+
90
+ # Has many
91
+
92
+ class << self
93
+
94
+ def has_many(collection_name, options={})
95
+ collection_name = collection_name.to_s
96
+ path = collection_name
97
+ individual_name = collection_name.singularize
98
+ class_name = options.fetch(:class_name, individual_name.classify)
99
+
100
+ require "unfuddle/#{individual_name}"
101
+
102
+ class_eval <<-RUBY
103
+ def #{collection_name}
104
+ @#{collection_name} ||= get('#{path}').json.map { |attributes| #{class_name}.new(attributes) }
105
+ end
106
+
107
+ def #{individual_name}(id)
108
+ attributes = find_#{individual_name}(id)
109
+ #{class_name}.new(attributes) if attributes
110
+ end
111
+
112
+ def find_#{individual_name}(id)
113
+ response = get("#{path}/\#{id}")
114
+
115
+ return nil if response.status == 404
116
+ Unfuddle.assert_response!(200, response)
117
+
118
+ response.json
119
+ end
120
+
121
+ def new_#{individual_name}(attributes)
122
+ #{class_name}.new(attributes)
123
+ end
124
+
125
+ def create_#{individual_name}(params)
126
+ instance = #{class_name}.new(params)
127
+ response = post('#{path}', instance)
128
+ Unfuddle.assert_response!(201, response)
129
+
130
+ instance.__set_attributes(response.json)
131
+
132
+ unless instance.id
133
+ id = response.location.chomp("/")[/\\d+$/].to_i
134
+ instance.__set_attributes("id" => id) if id > 0
135
+ end
136
+
137
+ @#{collection_name}.push(instance) if @#{collection_name}
138
+ instance
139
+ end
140
+ RUBY
141
+ end
142
+
143
+ end
144
+
145
+
146
+
147
+ # Nest Unfuddle requests
148
+
149
+ def relative_path
150
+ raise NotImplementedError
151
+ end
152
+
153
+ [:get, :post, :put, :delete].each do |method|
154
+ module_eval <<-RUBY
155
+ def #{method}(path, *args)
156
+ Unfuddle.#{method}(relative_path + "/" + path, *args)
157
+ end
158
+ RUBY
159
+ end
160
+
161
+
162
+
163
+ # Serialization
164
+
165
+ def to_params
166
+ attributes
167
+ end
168
+
169
+ def singular_name
170
+ self.class.name[/[^:]*$/].tableize.singularize
171
+ end
172
+
173
+ def to_xml
174
+ to_params.to_xml(root: singular_name)
175
+ end
176
+
177
+ def to_json
178
+ JSON.dump({singular_name => to_params})
179
+ end
180
+
181
+ def fetch!
182
+ response = get(get_path)
183
+ Unfuddle.assert_response!(200, response)
184
+ __set_attributes(response.json)
185
+
186
+ rescue InvalidResponseError
187
+ binding.pry if binding.respond_to?(:pry)
188
+ raise $!
189
+ end
190
+
191
+ def save!
192
+ put put_path, self
193
+ end
194
+
195
+ def destroy!
196
+ delete delete_path
197
+ end
198
+
199
+
200
+
201
+ def get_path
202
+ ""
203
+ end
204
+
205
+ def put_path
206
+ ""
207
+ end
208
+
209
+ def delete_path
210
+ ""
211
+ end
212
+
213
+
214
+
215
+ private
216
+
217
+ def _attributes
218
+ fetch! if unfetched?
219
+ @attributes
220
+ end
221
+
222
+ end
223
+ end
@@ -0,0 +1,13 @@
1
+ require 'unfuddle/base'
2
+
3
+ class Unfuddle
4
+ class Comment < Base
5
+
6
+ def relative_path
7
+ "projects/#{project_id}/tickets/#{parent_id}/comments/#{id}"
8
+ end
9
+
10
+ attr_accessor :project_id
11
+
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ require 'unfuddle/base'
2
+
3
+ class Unfuddle
4
+ class Component < Base
5
+
6
+ def relative_path
7
+ "projects/#{project_id}/components/#{id}"
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,67 @@
1
+ class Unfuddle
2
+ class Configuration
3
+
4
+
5
+ [:subdomain, :username, :password, :logger, :include_associations, :include_closed_on, :timeout].each do |attribute|
6
+ module_eval <<-RUBY
7
+ def #{attribute}(*arg)
8
+ set_value :#{attribute}, arg.first if arg.any?
9
+ get_value :#{attribute}
10
+ end
11
+
12
+ def #{attribute}=(value)
13
+ set_value :#{attribute}, value
14
+ end
15
+ RUBY
16
+ end
17
+
18
+
19
+ alias :include_associations? :include_associations
20
+ alias :include_closed_on? :include_closed_on
21
+
22
+
23
+ def merge(options)
24
+ to_h.merge(options)
25
+ end
26
+
27
+ def to_h
28
+ { subdomain: subdomain,
29
+ username: username,
30
+ password: password,
31
+ include_associations: include_associations,
32
+ include_closed_on: include_closed_on,
33
+ logged: logger,
34
+ timeout: timeout }
35
+ end
36
+
37
+ def from_options(options)
38
+ options = options.with_indifferent_access
39
+ self.subdomain = options[:subdomain] if options.key?(:subdomain)
40
+ self.username = options[:username] if options.key?(:username)
41
+ self.password = options[:password] if options.key?(:password)
42
+ self.include_associations = options[:include_associations] if options.key?(:include_associations)
43
+ self.include_closed_on = options[:include_closed_on] if options.key?(:include_closed_on)
44
+ self.timeout = options.fetch :timeout, 120
45
+ self.logger = options.fetch :logger, Unfuddle::Configuration::Logger.new
46
+ end
47
+
48
+
49
+ class Logger
50
+ def info(s)
51
+ puts s
52
+ end
53
+ end
54
+
55
+
56
+ private
57
+
58
+ def set_value(attribute, value)
59
+ instance_variable_set(:"@#{attribute}", value)
60
+ end
61
+
62
+ def get_value(attribute)
63
+ instance_variable_get(:"@#{attribute}")
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,11 @@
1
+ require 'unfuddle/base'
2
+
3
+ class Unfuddle
4
+ class CustomFieldValue < Base
5
+
6
+ def relative_path
7
+ "projects/#{project_id}/custom_field_values/#{id}"
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,59 @@
1
+ class Unfuddle
2
+
3
+ module Error
4
+ end
5
+
6
+ class ConfigurationError < StandardError
7
+ include ::Unfuddle::Error
8
+ end
9
+
10
+ class ConnectionError < StandardError
11
+ include ::Unfuddle::Error
12
+ end
13
+
14
+ class TimeoutError < ConnectionError
15
+ end
16
+
17
+
18
+
19
+ class InvalidResponseError < StandardError
20
+ include ::Unfuddle::Error
21
+
22
+ def initialize(response)
23
+ @response = response
24
+ end
25
+
26
+ attr_reader :response
27
+
28
+ def message
29
+ response.body
30
+ end
31
+
32
+ end
33
+
34
+ class ServerError < InvalidResponseError
35
+ end
36
+
37
+ class UnauthorizedError < InvalidResponseError
38
+
39
+ def message
40
+ "The user '#{Unfuddle.instance.username}' does not have permission to access this resource"
41
+ end
42
+
43
+ end
44
+
45
+
46
+
47
+ class UndefinedCustomField < ArgumentError
48
+ include ::Unfuddle::Error
49
+ end
50
+
51
+ class UndefinedCustomFieldValue < ArgumentError
52
+ include ::Unfuddle::Error
53
+ end
54
+
55
+ class UndefinedSeverity < ArgumentError
56
+ include ::Unfuddle::Error
57
+ end
58
+
59
+ end
@@ -0,0 +1,68 @@
1
+ require 'active_support/core_ext/array/wrap'
2
+
3
+
4
+ class Unfuddle
5
+ module HasTickets
6
+
7
+ def find_ticket_by_number(number)
8
+ response = get("tickets/by_number/#{number}")
9
+
10
+ return nil if response.status == 404
11
+ Unfuddle.assert_response!(200, response)
12
+
13
+ response.json
14
+ end
15
+
16
+ def find_tickets!(*conditions)
17
+ raise ArgumentError.new("No conditions supplied: that's probably not good") if conditions.none?
18
+ path = "ticket_reports/dynamic.json"
19
+ path << "?conditions_string=#{construct_ticket_query(*conditions)}"
20
+ fields = %w{number summary description reporter_email resolution milestone_id created_at due_on severity_id component_id}
21
+ fields << "associations" if Unfuddle.include_associations?
22
+ fields << "closed_on" if Unfuddle.include_closed_on?
23
+ path << "&fields_string=#{fields.join(",")}" if fields.any?
24
+ response = get(path)
25
+
26
+ Unfuddle.assert_response!(200, response)
27
+
28
+ ticket_report = response.json
29
+ group0 = ticket_report.fetch("groups", [])[0] || {}
30
+ group0.fetch("tickets", [])
31
+ end
32
+
33
+
34
+
35
+ def construct_ticket_query(*conditions)
36
+ conditions_string = []
37
+ conditions.each do |condition|
38
+ case condition
39
+ when Hash
40
+ conditions_string.concat(condition.map { |key, value| Array.wrap(value).map { |value| create_condition_string(key, value) }.join("|") })
41
+ when Array
42
+ key, value = condition
43
+ conditions_string.push(Array.wrap(value).map { |value| create_condition_string(key, value) }.join("|"))
44
+ else
45
+ conditions_string.push(condition)
46
+ end
47
+ end
48
+ conditions_string.join("%2C")
49
+ end
50
+
51
+ def create_condition_string(key, value)
52
+ comparison = "eq"
53
+ comparison, value = "neq", value.value if value.is_a?(Neq)
54
+ key, value = prepare_key_and_value_for_conditions_string(key, value)
55
+ "#{key}-#{comparison}-#{value}"
56
+ end
57
+
58
+ def prepare_key_and_value_for_conditions_string(key, value)
59
+
60
+ # If the value is an id, convert it to a number
61
+ value = value.to_i if value.is_a?(String) && value =~ /^\d+$/
62
+
63
+ [key, value]
64
+ end
65
+
66
+ end
67
+
68
+ end
@@ -0,0 +1,11 @@
1
+ require 'unfuddle/base'
2
+
3
+ class Unfuddle
4
+ class Milestone < Base
5
+
6
+ def relative_path
7
+ "projects/#{project_id}/milestones/#{id}"
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,24 @@
1
+ class Unfuddle
2
+ module NeqHelper
3
+
4
+ def neq(arg)
5
+ Neq.new(arg)
6
+ end
7
+
8
+ end
9
+
10
+ class Neq
11
+
12
+ def initialize(value)
13
+ @value = value
14
+ end
15
+
16
+ def to_s
17
+ "neq(#{value.inspect})"
18
+ end
19
+
20
+ attr_reader :value
21
+
22
+ end
23
+ end
24
+
@@ -0,0 +1,24 @@
1
+ require 'unfuddle/base'
2
+
3
+
4
+ class Unfuddle
5
+ class Person < Base
6
+
7
+ def self.all(options={})
8
+ url = options[:including_removed] == true ? "people.json?removed=true" : "people.json"
9
+ response = Unfuddle.get(url)
10
+
11
+ if response.status == 404
12
+ nil
13
+ else
14
+ Unfuddle.assert_response!(200, response)
15
+ response.json.map { |attributes| self.new(attributes) }
16
+ end
17
+ end
18
+
19
+ def relative_path
20
+ "people/#{id}"
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,136 @@
1
+ require 'unfuddle/base'
2
+ require 'unfuddle/has_tickets'
3
+
4
+
5
+ class Unfuddle
6
+ class Project < Base
7
+ include HasTickets
8
+
9
+ def self.all
10
+ @projects ||= begin
11
+ response = Unfuddle.get('projects')
12
+
13
+ if response.status == 404
14
+ nil
15
+ else
16
+ Unfuddle.assert_response!(200, response)
17
+ response.json.map { |attributes| self.new(attributes) }
18
+ end
19
+ end
20
+ end
21
+
22
+ def self.fetch(id)
23
+ response = Unfuddle.get("projects/#{id}")
24
+
25
+ if response.status == 404
26
+ nil
27
+ else
28
+ Unfuddle.assert_response!(200, response)
29
+ self.new response.json
30
+ end
31
+ end
32
+
33
+ def relative_path
34
+ "projects/#{id}"
35
+ end
36
+
37
+
38
+
39
+ find_by :title
40
+
41
+ has_many :custom_field_values
42
+ has_many :severities
43
+ has_many :components
44
+ has_many :ticket_reports
45
+ has_many :tickets
46
+ has_many :milestones
47
+
48
+
49
+
50
+ def open_milestones
51
+ @open_milestones ||= get("projects/#{id}/milestones/upcoming").json.map { |attributes| Milestone.new(attributes) }
52
+ end
53
+
54
+
55
+
56
+ def custom_fields
57
+ { 1 => ticket_field1_active ? ticket_field1_title : nil,
58
+ 2 => ticket_field2_active ? ticket_field2_title : nil,
59
+ 3 => ticket_field3_active ? ticket_field3_title : nil }
60
+ end
61
+
62
+ def custom_fields_defined
63
+ custom_fields.values.compact
64
+ end
65
+
66
+ def custom_field_defined?(field_title)
67
+ custom_fields_defined.member?(field_title)
68
+ end
69
+
70
+ def first_available_custom_field
71
+ (1..3).find { |n| custom_fields[n].nil? }
72
+ end
73
+
74
+ def number_of_custom_field_named!(name)
75
+ number_of_custom_field_named(name) || (raise UndefinedCustomField, "A custom field named \"#{name}\" is not defined!")
76
+ end
77
+
78
+ def number_of_custom_field_named(name)
79
+ custom_fields.key(name)
80
+ end
81
+
82
+
83
+
84
+ def find_custom_field_value_by_value!(field, value)
85
+ n = number_of_custom_field_named!(field)
86
+ result = custom_field_values.find { |cfv| cfv.field_number == n && cfv.value == value }
87
+ raise UndefinedCustomFieldValue, "\"#{value}\" is not a value for the custom field \"#{field}\"!" unless result
88
+ result
89
+ end
90
+
91
+ def find_custom_field_value_by_id!(field, id)
92
+ n = number_of_custom_field_named!(field)
93
+ result = custom_field_values.find { |cfv| cfv.field_number == n && cfv.id == id }
94
+ raise UndefinedCustomFieldValue, "\"#{id}\" is not the id of a value for the custom field \"#{field}\"!" unless result
95
+ result
96
+ end
97
+
98
+
99
+
100
+ def find_severity_by_name!(name)
101
+ find_severity_by_name(name) || (raise UndefinedSeverity, "A severity named \"#{name}\" is not defined!")
102
+ end
103
+
104
+ def find_severity_by_name(name)
105
+ severities.find { |severity| severity.name == name }
106
+ end
107
+
108
+
109
+
110
+ def prepare_key_and_value_for_conditions_string(key, value)
111
+ key, value = super
112
+
113
+ # If the value is the name of a severity, try to look it up
114
+ value = find_severity_by_name!(value).id if key == :severity && value.is_a?(String)
115
+
116
+ # If the key is a custom field, look up the key and value
117
+ if key.is_a?(String)
118
+ value = find_custom_field_value_by_value!(key, value).id unless value.is_a?(Fixnum)
119
+ key = get_key_for_custom_field_named!(key)
120
+ end
121
+
122
+ [key, value]
123
+ end
124
+
125
+ def get_key_for_custom_field_named!(name)
126
+ "field_#{number_of_custom_field_named!(name)}"
127
+ end
128
+
129
+ def get_ticket_attribute_for_custom_value_named!(name)
130
+ "field#{number_of_custom_field_named!(name)}_value_id"
131
+ end
132
+
133
+
134
+
135
+ end
136
+ end
@@ -0,0 +1,49 @@
1
+ require 'unfuddle/error'
2
+
3
+
4
+ class Unfuddle
5
+ class Response
6
+
7
+
8
+ def initialize(faraday_response)
9
+ @faraday_response = faraday_response
10
+ end
11
+
12
+ def status
13
+ faraday_response.status
14
+ end
15
+
16
+ def server_error?
17
+ status == 500
18
+ end
19
+
20
+ def unauthorized?
21
+ status == 401
22
+ end
23
+
24
+ def body
25
+ faraday_response.body
26
+ end
27
+
28
+ def location
29
+ faraday_response["location"]
30
+ end
31
+
32
+ def json
33
+ @json ||= begin
34
+ json = self.class.normalized_body(body)
35
+ json.empty? ? {} : JSON.load(json)
36
+ end
37
+ end
38
+
39
+ def self.normalized_body(body)
40
+ body.gsub(/\u0000/, "").strip
41
+ end
42
+
43
+
44
+ private
45
+
46
+ attr_reader :faraday_response
47
+
48
+ end
49
+ end
@@ -0,0 +1,11 @@
1
+ require 'unfuddle/base'
2
+
3
+ class Unfuddle
4
+ class Severity < Base
5
+
6
+ def relative_path
7
+ "projects/#{project_id}/severities/#{id}"
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ require 'unfuddle/base'
2
+
3
+ class Unfuddle
4
+ class Ticket < Base
5
+
6
+ def relative_path
7
+ "projects/#{project_id}/tickets/#{id}"
8
+ end
9
+
10
+ has_many :comments
11
+
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ require 'unfuddle/base'
2
+
3
+ class Unfuddle
4
+ class TicketReport < Base
5
+
6
+ def relative_path
7
+ "projects/#{parent_id}/ticket_reports/#{id}"
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ class Unfuddle
2
+ VERSION = "0.7.0"
3
+ end
@@ -0,0 +1,6 @@
1
+ require "rubygems"
2
+ require "simplecov"
3
+ require "rails"
4
+ require "rails/test_help"
5
+ require "active_support/core_ext"
6
+ require "turn"
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "unfuddle/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "boblail-unfuddle"
7
+ s.version = Unfuddle::VERSION
8
+ s.authors = ["Bob Lail"]
9
+ s.email = ["bob.lailfamily@gmail.com"]
10
+
11
+ s.homepage = "http://boblail.github.com/unfuddle/"
12
+ s.summary = %q{A library for communicating with Unfuddle}
13
+ s.description = %q{A library for communicating with Unfuddle}
14
+
15
+ s.add_dependency "activesupport"
16
+ s.add_dependency "builder"
17
+ s.add_dependency "faraday", "~> 0.8.8"
18
+
19
+ s.add_development_dependency "rails"
20
+ s.add_development_dependency "turn"
21
+ s.add_development_dependency "simplecov"
22
+
23
+ s.files = `git ls-files`.split("\n")
24
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
26
+ s.require_paths = ["lib"]
27
+ end
metadata ADDED
@@ -0,0 +1,151 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: boblail-unfuddle
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.7.0
5
+ platform: ruby
6
+ authors:
7
+ - Bob Lail
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-09-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
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: builder
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: faraday
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.8.8
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.8.8
55
+ - !ruby/object:Gem::Dependency
56
+ name: rails
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: turn
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: A library for communicating with Unfuddle
98
+ email:
99
+ - bob.lailfamily@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - Gemfile
106
+ - Gemfile.lock
107
+ - Rakefile
108
+ - lib/unfuddle.rb
109
+ - lib/unfuddle/base.rb
110
+ - lib/unfuddle/comment.rb
111
+ - lib/unfuddle/component.rb
112
+ - lib/unfuddle/configuration.rb
113
+ - lib/unfuddle/custom_field_value.rb
114
+ - lib/unfuddle/error.rb
115
+ - lib/unfuddle/has_tickets.rb
116
+ - lib/unfuddle/milestone.rb
117
+ - lib/unfuddle/neq.rb
118
+ - lib/unfuddle/person.rb
119
+ - lib/unfuddle/project.rb
120
+ - lib/unfuddle/response.rb
121
+ - lib/unfuddle/severity.rb
122
+ - lib/unfuddle/ticket.rb
123
+ - lib/unfuddle/ticket_report.rb
124
+ - lib/unfuddle/version.rb
125
+ - test/test_helper.rb
126
+ - unfuddle.gemspec
127
+ homepage: http://boblail.github.com/unfuddle/
128
+ licenses: []
129
+ metadata: {}
130
+ post_install_message:
131
+ rdoc_options: []
132
+ require_paths:
133
+ - lib
134
+ required_ruby_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ required_rubygems_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ requirements: []
145
+ rubyforge_project:
146
+ rubygems_version: 2.2.2
147
+ signing_key:
148
+ specification_version: 4
149
+ summary: A library for communicating with Unfuddle
150
+ test_files:
151
+ - test/test_helper.rb