arusarka-mingle4r 0.2.5 → 0.2.7
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.
- data/MIT-LICENSE +21 -0
- data/Rakefile +23 -0
- data/TODO.txt +4 -0
- data/lib/mingle4r.rb +23 -0
- data/lib/mingle4r/card.rb +139 -0
- data/lib/mingle4r/card/attachment.rb +47 -0
- data/lib/mingle4r/common_class_methods.rb +219 -0
- data/lib/mingle4r/common_dyn_class_instance_methods.rb +40 -0
- data/lib/mingle4r/helpers.rb +33 -0
- data/lib/mingle4r/mingle_client.rb +106 -0
- data/lib/mingle4r/project.rb +64 -0
- data/lib/mingle4r/property_definition.rb +18 -0
- data/lib/mingle4r/user.rb +5 -0
- data/lib/mingle4r/version.rb +11 -0
- data/lib/mingle4r/wiki.rb +7 -0
- data/lib/mingle_resource.rb +2 -0
- data/spec/mingle4r/card/attachment_spec.rb +48 -0
- data/spec/mingle4r/card_spec.rb +40 -0
- data/spec/mingle4r/common_class_methods_spec.rb +104 -0
- data/spec/mingle4r/helpers_spec.rb +20 -0
- data/spec/mingle4r/project_spec.rb +20 -0
- data/spec/mingle4r/property_definition_spec.rb +30 -0
- data/spec/mingle4r/version_spec.rb +7 -0
- data/spec/mingle4r/wiki_spec.rb +11 -0
- data/spec/mingle4r_spec.rb +7 -0
- data/spec/spec_helper.rb +3 -0
- data/test/integration/test.rb +39 -0
- data/test/integration/test_adding_comment.rb +9 -0
- data/test/integration/test_card_filter.rb +7 -0
- data/test/integration/test_card_transition.rb +9 -0
- data/test/integration/test_getting_users.rb +10 -0
- data/test/integration/test_uploading_attachment.rb +9 -0
- data/test/integration/test_wiki.rb +7 -0
- metadata +34 -2
- data/History.txt +0 -33
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2009 Arusarka Haldar
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rake'
|
5
|
+
require 'spec/rake/spectask'
|
6
|
+
require 'rake/gempackagetask'
|
7
|
+
|
8
|
+
namespace :gem do
|
9
|
+
desc "Builds the gem"
|
10
|
+
task :build do
|
11
|
+
file_name = "#{File.dirname(__FILE__)}/mingle4r.gemspec"
|
12
|
+
spec = Gem::Specification.load(file_name)
|
13
|
+
Gem::Builder.new(spec).build
|
14
|
+
file = FileList["#{File.dirname(__FILE__)}/mingle4r*.gem"]
|
15
|
+
mv file.to_a, "#{File.dirname(__FILE__)}/pkg"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# task : run specs
|
20
|
+
Spec::Rake::SpecTask.new do |t|
|
21
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
22
|
+
t.verbose = true
|
23
|
+
end
|
data/TODO.txt
ADDED
data/lib/mingle4r.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
$:.unshift File.expand_path(File.dirname(__FILE__))
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
require 'rubygems'
|
5
|
+
require 'active_resource'
|
6
|
+
require 'net/http'
|
7
|
+
|
8
|
+
# This module should be used to interact with mingle. Look in the readme for examples.
|
9
|
+
module Mingle4r
|
10
|
+
AUTHOR = 'Asur'
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'mingle_resource'
|
14
|
+
require 'mingle4r/version'
|
15
|
+
require 'mingle4r/common_class_methods'
|
16
|
+
require 'mingle4r/common_dyn_class_instance_methods'
|
17
|
+
require 'mingle4r/helpers'
|
18
|
+
require 'mingle4r/user'
|
19
|
+
require 'mingle4r/card'
|
20
|
+
require 'mingle4r/project'
|
21
|
+
require 'mingle4r/property_definition'
|
22
|
+
require 'mingle4r/wiki'
|
23
|
+
require 'mingle4r/mingle_client'
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'mingle4r/card/attachment'
|
2
|
+
|
3
|
+
module Mingle4r
|
4
|
+
class Card
|
5
|
+
module ClassMethods
|
6
|
+
def find_without_pagination(*args)
|
7
|
+
scope = args.slice!(0)
|
8
|
+
options = args.slice!(0) || {}
|
9
|
+
options[:params] ||= {}
|
10
|
+
options[:params].merge!({:page => 'all'})
|
11
|
+
|
12
|
+
# call ActiveResource::Base::find with proper options
|
13
|
+
find(scope, options)
|
14
|
+
end
|
15
|
+
|
16
|
+
# applies an mql filter on card types. Look at https://mingle05.thoughtworks.com/help/mql_reference.html
|
17
|
+
# for reference
|
18
|
+
def apply_filter(filter_string)
|
19
|
+
find_without_pagination(:all, :params => {'filters[mql]'.to_sym => filter_string})
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module InstanceMethods
|
24
|
+
def attachments(refresh = false)
|
25
|
+
return @attachments if(!refresh && @attachments_cached)
|
26
|
+
attachment_site = File.join(self.class.site.to_s, "cards/#{self.number()}").to_s
|
27
|
+
Mingle4r::Card::Attachment.site = attachment_site
|
28
|
+
Mingle4r::Card::Attachment.user = self.class.user
|
29
|
+
Mingle4r::Card::Attachment.password = self.class.password
|
30
|
+
attachment_class = Mingle4r::Card::Attachment.send(:create_resource_class)
|
31
|
+
@attachments = attachment_class.find(:all)
|
32
|
+
@attachments_cached = true
|
33
|
+
@attachments
|
34
|
+
end
|
35
|
+
|
36
|
+
def upload_attachment(file_path)
|
37
|
+
attachment_uri = URI.parse(File.join(self.class.site.to_s, "cards/#{self.number()}/attachments.xml"))
|
38
|
+
|
39
|
+
http = Net::HTTP.new(attachment_uri.host, attachment_uri.port)
|
40
|
+
http.use_ssl = attachment_uri.is_a?(URI::HTTPS)
|
41
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if http.use_ssl
|
42
|
+
|
43
|
+
basic_encode = 'Basic ' + ["#{self.class.user}:#{self.class.password}"].pack('m').delete("\r\n")
|
44
|
+
|
45
|
+
post_headers = {
|
46
|
+
'Authorization' => basic_encode,
|
47
|
+
'Content-Type' => 'multipart/form-data; boundary=----------XnJLe9ZIbbGUYtzPQJ16u1'
|
48
|
+
}
|
49
|
+
|
50
|
+
file_content = IO.read(file_path)
|
51
|
+
|
52
|
+
post_body = <<EOS
|
53
|
+
------------XnJLe9ZIbbGUYtzPQJ16u1\r
|
54
|
+
Content-Disposition: form-data; name="file"; filename="#{File.basename(file_path)}"\r
|
55
|
+
Content-Type: application/octet-stream\r
|
56
|
+
Content-Length: #{file_content.size}\r
|
57
|
+
\r
|
58
|
+
#{file_content}\r
|
59
|
+
------------XnJLe9ZIbbGUYtzPQJ16u1--\r
|
60
|
+
EOS
|
61
|
+
|
62
|
+
http.post(attachment_uri.path, post_body, post_headers)
|
63
|
+
end
|
64
|
+
|
65
|
+
# returns back the version of the card given. If an invalid version is given, the latest
|
66
|
+
# version is returned, takes a number or :next or :before
|
67
|
+
def at_version(version_no)
|
68
|
+
version_2_find = 0
|
69
|
+
case version_no
|
70
|
+
when :before
|
71
|
+
version_2_find = self.version.to_i - 1
|
72
|
+
when :next
|
73
|
+
version_2_find = self.version.to_i + 1
|
74
|
+
else
|
75
|
+
version_2_find = version_no.to_i
|
76
|
+
end
|
77
|
+
self.class.find(self.number, :params => {:version => version_2_find})
|
78
|
+
end
|
79
|
+
|
80
|
+
# adds a comment to a card.
|
81
|
+
def add_comment(comment)
|
82
|
+
comment_uri = URI.parse(File.join(self.class.site.to_s, "cards/add_comment?card_id=#{self.id}"))
|
83
|
+
|
84
|
+
http = Net::HTTP.new(comment_uri.host, comment_uri.port)
|
85
|
+
http.use_ssl = comment_uri.is_a?(URI::HTTPS)
|
86
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if http.use_ssl
|
87
|
+
|
88
|
+
basic_encode = 'Basic ' + ["#{self.class.user}:#{self.class.password}"].pack('m').delete("\r\n")
|
89
|
+
|
90
|
+
post_headers = {
|
91
|
+
'Authorization' => basic_encode,
|
92
|
+
'Content-Type' => 'application/x-www-form-urlencoded; charset=UTF-8'
|
93
|
+
}
|
94
|
+
|
95
|
+
post_body = "comment=#{comment}&card_id=#{self.id}"
|
96
|
+
|
97
|
+
http.post(comment_uri.path, post_body, post_headers)
|
98
|
+
end
|
99
|
+
|
100
|
+
# TODO - Check if working with https
|
101
|
+
# Executes the given transition on the card.
|
102
|
+
# Example :
|
103
|
+
# defect_card.execute_transition(:transition_name => 'Close Defect', :Owner => nil, :Status => 'Closed', :transition_comment => comment)
|
104
|
+
# transition_comment is mandatory if the transition is set that way.
|
105
|
+
# after transition 'Owner' would have value 'Not Set' and 'Status' would be 'Closed' for defect card
|
106
|
+
def execute_transition(args_hash)
|
107
|
+
project_id = File.basename(self.class.site.to_s)
|
108
|
+
transition_name = args_hash.delete(:transition_name)
|
109
|
+
raise 'Transition name for given' unless transition_name
|
110
|
+
transition_uri = URI.parse(File.join(self.class.site.to_s, 'transition_executions.xml'))
|
111
|
+
|
112
|
+
# create the form data
|
113
|
+
form_data = {
|
114
|
+
'transition_execution[transition]' => transition_name,
|
115
|
+
'transition_execution[card]' => self.number.to_s
|
116
|
+
}
|
117
|
+
comment = args_hash.delete(:transition_comment)
|
118
|
+
form_data['transition_execution[comment]'] = Helpers.encode2html(comment) if comment
|
119
|
+
args_hash.each do |key, value|
|
120
|
+
form_data['transition_execution[properties][][name]'] = Helpers.encode2html(key.to_s)
|
121
|
+
form_data['transition_execution[properties][][value]'] = Helpers.encode2html(value.to_s)
|
122
|
+
end
|
123
|
+
|
124
|
+
req = Net::HTTP::Post.new(transition_uri.path)
|
125
|
+
req.basic_auth self.class.user, self.class.password
|
126
|
+
req.set_form_data(form_data)
|
127
|
+
|
128
|
+
Net::HTTP.new(transition_uri.host, transition_uri.port).start { |http| http.request(req) }
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
def boundary
|
133
|
+
'----------XnJLe9ZIbbGUYtzPQJ16u1'
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
extend Mingle4r::CommonClassMethods
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Mingle4r
|
2
|
+
class Card
|
3
|
+
class Attachment
|
4
|
+
module InstanceMethods
|
5
|
+
# downloads the attachment. It an additional file path is given it saves it at the
|
6
|
+
# given path. The given path should be writable
|
7
|
+
def download(file_name = nil)
|
8
|
+
collection_uri = self.class.site
|
9
|
+
rel_down_url = self.url
|
10
|
+
base_url = "#{collection_uri.scheme}://#{collection_uri.host}:#{collection_uri.port}/"
|
11
|
+
down_uri = URI.join(base_url, rel_down_url)
|
12
|
+
req = Net::HTTP::Get.new(down_uri.path)
|
13
|
+
req.basic_auth self.class.user, self.class.password
|
14
|
+
begin
|
15
|
+
res = Net::HTTP.start(down_uri.host, down_uri.port) { |http| http.request(req) }
|
16
|
+
file_name ||= self.file_name()
|
17
|
+
File.open(file_name, 'w') { |f| f.print(res.body) }
|
18
|
+
rescue Exception => e
|
19
|
+
e.message
|
20
|
+
end
|
21
|
+
end # download
|
22
|
+
|
23
|
+
# alias for file_name
|
24
|
+
def name
|
25
|
+
file_name()
|
26
|
+
end
|
27
|
+
|
28
|
+
# so that active resource tries to find by proper id
|
29
|
+
def id
|
30
|
+
name()
|
31
|
+
end
|
32
|
+
|
33
|
+
# This method had to be overriden.
|
34
|
+
# normal active resource destroy doesn't work as mingle site for deleting attachments doesn't end with .xml.
|
35
|
+
def destroy
|
36
|
+
connection = self.send(:connection)
|
37
|
+
# deletes the attachment by removing .xml at the end
|
38
|
+
connection.delete(self.send(:element_path).gsub(/\.xml\z/, ''))
|
39
|
+
end
|
40
|
+
alias_method :delete, :destroy
|
41
|
+
end #module InstanceMethods
|
42
|
+
|
43
|
+
extend Mingle4r::CommonClassMethods
|
44
|
+
|
45
|
+
end # class Attachment
|
46
|
+
end # class Card
|
47
|
+
end # module Mingle4r
|
@@ -0,0 +1,219 @@
|
|
1
|
+
module Mingle4r
|
2
|
+
# ActiveResource makes connecting to rest resources very easy. However it has one problem
|
3
|
+
# and a big one at that. If you try setting the authentication credentials or the site or
|
4
|
+
# collection name, element name for the class for the second time it doesn't work. E.g.
|
5
|
+
#
|
6
|
+
# class Person < ActiveResource::base
|
7
|
+
# self.site = 'http://localhost:9090/'
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
# After sometime you change it to
|
11
|
+
#
|
12
|
+
# Person.site = 'https://org-server/my_proj/'
|
13
|
+
# Person.user = 'admin'
|
14
|
+
# Person.password = 'secret'
|
15
|
+
#
|
16
|
+
# Then you do
|
17
|
+
#
|
18
|
+
# Person.find(:all) => It bombs
|
19
|
+
#
|
20
|
+
# This module provides a mechanism by which you can get rid of this problem. Extend this
|
21
|
+
# class in the actual class itself. Do not extend the extended class from ActiveResource::Base.
|
22
|
+
#
|
23
|
+
# E.g.
|
24
|
+
#
|
25
|
+
# class Person
|
26
|
+
# extend CommonClassMethods
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# set the credentials
|
30
|
+
#
|
31
|
+
# Person.site = 'http://localhost:8080'
|
32
|
+
# Person.user = 'foo'
|
33
|
+
# Person.password = 'bar'
|
34
|
+
#
|
35
|
+
# Thats it. Now create some objects
|
36
|
+
#
|
37
|
+
# asur = Person.new(:name => 'Asur', :job => 'fooling around', :status => 'Single and ready 2 mingle')
|
38
|
+
# asur.save
|
39
|
+
#
|
40
|
+
# Now change the class attributes
|
41
|
+
#
|
42
|
+
# Person.site = 'https://org-server/mingle'
|
43
|
+
# Person.collection_name = 'boring_people'
|
44
|
+
#
|
45
|
+
# Now instantiate an object
|
46
|
+
#
|
47
|
+
# rakhshas = Person.new(:name => 'Rakhshas', :job => 'eating people', :status => 'just woke up and hungry')
|
48
|
+
# rakhshas.save => Voila !!!!!!! it works
|
49
|
+
#
|
50
|
+
# CUSTOMIZATIONS
|
51
|
+
# --------------
|
52
|
+
#
|
53
|
+
# No amount of wrapping can provide very detailed customizations. Either you have a lot of methods
|
54
|
+
# that are not being used or there is hardly anything at all. To oversome this problem this module
|
55
|
+
# was written to provide only those methods which are common to most active resource objects.
|
56
|
+
# However if you want to have a little more control over your active resource objects its very easy.
|
57
|
+
# Here's how you would do it normally
|
58
|
+
#
|
59
|
+
# class Person < ActiveResource::Base
|
60
|
+
# def self.count
|
61
|
+
# find(:all).size
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
# def occupation
|
65
|
+
# return job if job
|
66
|
+
# 'Unemployed'
|
67
|
+
# end
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
# To do the same thing, here's how you do it using this library
|
71
|
+
#
|
72
|
+
# class Person
|
73
|
+
# module ClassMethods
|
74
|
+
# def count
|
75
|
+
# find(:all).size
|
76
|
+
# end
|
77
|
+
# end
|
78
|
+
#
|
79
|
+
# module InstanceMethods
|
80
|
+
# def occupation
|
81
|
+
# return job if job
|
82
|
+
# 'Unemployed'
|
83
|
+
# end
|
84
|
+
# end
|
85
|
+
# extend CommonClassMethods
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
# The instance methods will be available as instance methods in the objects created, class methods
|
89
|
+
# will be available as class methods in the class of the object.
|
90
|
+
|
91
|
+
module CommonClassMethods
|
92
|
+
attr_reader :site, :user, :password
|
93
|
+
|
94
|
+
# creates an object of the class in which this module is extended
|
95
|
+
def new(args = {})
|
96
|
+
# @resource_class = create_resource_class() # should this be commented
|
97
|
+
@resource_class.new(args)
|
98
|
+
end
|
99
|
+
|
100
|
+
# sets the site for the class in which this module is extended
|
101
|
+
def site=(site)
|
102
|
+
if site != self.site
|
103
|
+
@site = site
|
104
|
+
uri = URI.parse(site)
|
105
|
+
@user = URI.decode(uri.user) if(uri.user)
|
106
|
+
@password = URI.decode(uri.password) if(uri.password)
|
107
|
+
@resource_class = self.send(:create_resource_class)
|
108
|
+
end
|
109
|
+
@site
|
110
|
+
end
|
111
|
+
|
112
|
+
# sets the user for the class in which this module is extended
|
113
|
+
def user=(user)
|
114
|
+
if user != self.user
|
115
|
+
@user = user
|
116
|
+
@resource_class = self.send(:create_resource_class) if(site)
|
117
|
+
end
|
118
|
+
@user
|
119
|
+
end
|
120
|
+
|
121
|
+
# sets the password for the class in which this module is extended
|
122
|
+
def password=(password)
|
123
|
+
if password != self.password
|
124
|
+
@password = password
|
125
|
+
@resource_class = self.send(:create_resource_class) if(site)
|
126
|
+
end
|
127
|
+
@password
|
128
|
+
end
|
129
|
+
|
130
|
+
# sets the collection name for the class in which this module is extended
|
131
|
+
def collection_name=(collection_name)
|
132
|
+
if collection_name != self.collection_name
|
133
|
+
@collection_name = collection_name
|
134
|
+
end
|
135
|
+
@collection_name
|
136
|
+
end
|
137
|
+
|
138
|
+
# sets the elment name for the class in which this module is extended
|
139
|
+
def element_name=(element_name)
|
140
|
+
if element_name != self.element_name
|
141
|
+
@element_name = element_name
|
142
|
+
end
|
143
|
+
@element_name
|
144
|
+
end
|
145
|
+
|
146
|
+
# collection name for the class in which this module is extended
|
147
|
+
def collection_name
|
148
|
+
@collection_name || class_name.underscore.pluralize
|
149
|
+
end
|
150
|
+
|
151
|
+
# element name for the class in which this module is extended
|
152
|
+
def element_name
|
153
|
+
@element_name || class_name.underscore
|
154
|
+
end
|
155
|
+
|
156
|
+
# def all_attributes_set?
|
157
|
+
# site && user && password
|
158
|
+
# end
|
159
|
+
|
160
|
+
# routes to active resource find
|
161
|
+
def find(*args)
|
162
|
+
scope = args.slice!(0)
|
163
|
+
options = args.slice!(0) || {}
|
164
|
+
obj = @resource_class.find(scope, options)
|
165
|
+
obj
|
166
|
+
end
|
167
|
+
|
168
|
+
private
|
169
|
+
# creates an active resource class dynamically. All the attributes are set automatically. Avoid calling
|
170
|
+
# this method directly
|
171
|
+
def create_resource_class
|
172
|
+
# raise exceptions if any of site, user or password is not set
|
173
|
+
raise "Please set the site for #{self} class before using create_resource_class()." unless(self.site)
|
174
|
+
|
175
|
+
created_class = Class.new(MingleResource)
|
176
|
+
|
177
|
+
# set the resource options
|
178
|
+
created_class.site = self.site
|
179
|
+
created_class.user = self.user
|
180
|
+
created_class.password = self.password
|
181
|
+
created_class.collection_name = self.collection_name
|
182
|
+
created_class.element_name = self.element_name
|
183
|
+
|
184
|
+
created_class_name = "#{self}::#{class_name}#{Mingle4r::Helpers.fast_token()}"
|
185
|
+
eval "#{created_class_name} = created_class"
|
186
|
+
|
187
|
+
# includes a module called InstanceMethods in the class created dynamically
|
188
|
+
# if it is defined inside the wrapper class
|
189
|
+
inst_meth_mod_name = instance_methods_module_name()
|
190
|
+
created_class.send(:include, self.const_get(inst_meth_mod_name.to_sym)) if inst_meth_mod_name
|
191
|
+
created_class.send(:include, Mingle4r::CommonDynClassInstanceMethods)
|
192
|
+
|
193
|
+
# extends the class created dynamically with a module called ClassMethods if
|
194
|
+
# it is defined inside the wrapper class
|
195
|
+
class_meth_mod_name = class_methods_module_name()
|
196
|
+
created_class.extend(self.const_get(class_meth_mod_name)) if class_meth_mod_name
|
197
|
+
|
198
|
+
created_class
|
199
|
+
end
|
200
|
+
|
201
|
+
def class_name
|
202
|
+
self.name.split('::')[-1]
|
203
|
+
end
|
204
|
+
|
205
|
+
def instance_methods_module_name
|
206
|
+
inst_meth_mod_name = 'InstanceMethods'
|
207
|
+
self.constants.detect { |const| const.split('::')[-1] =~ /#{inst_meth_mod_name}/ }
|
208
|
+
end
|
209
|
+
|
210
|
+
def class_methods_module_name
|
211
|
+
class_meth_mod_name = 'ClassMethods'
|
212
|
+
self.constants.detect { |const| const.split('::')[-1] =~ /#{class_meth_mod_name}/ }
|
213
|
+
end
|
214
|
+
|
215
|
+
def method_missing(meth_id, *args, &block)
|
216
|
+
@resource_class.send(meth_id, *args, &block)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Mingle4r
|
2
|
+
# common dynamic class instance methods
|
3
|
+
module CommonDynClassInstanceMethods
|
4
|
+
# gets the value of a property. The property name can be given in several ways.
|
5
|
+
# suppose we are trying to get the property 'Iteration Number' as in mingle
|
6
|
+
#
|
7
|
+
# 1) give the name as seen card.property_value('Iteration Number')
|
8
|
+
#
|
9
|
+
# 2) give the property method name i.e. in the active resource object it would
|
10
|
+
# become by default 'cp_iteration_number' attribute unless set differently in
|
11
|
+
# Mingle
|
12
|
+
#
|
13
|
+
# 3) give the method a 'space separated' / 'camelcased' method name. e.g. - 'Iteration Number'
|
14
|
+
# 'IterationNumber'
|
15
|
+
def property_value(prop_name)
|
16
|
+
begin
|
17
|
+
column_name = PropertyDefinition.column_name_for(prop_name.to_s)
|
18
|
+
self.send(column_name.to_sym)
|
19
|
+
rescue NoMethodError
|
20
|
+
if self.attributes.has_key?(prop_name)
|
21
|
+
self.attributes[prop_name]
|
22
|
+
else
|
23
|
+
# try calling a underscorized method. eg 'Iteration Number' becomes
|
24
|
+
# 'iteration_number'
|
25
|
+
method_id = (prop_name.split(' ').map { |substring| substring.downcase }).join('_').underscore.to_sym
|
26
|
+
self.send(method_id)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def custom_properties
|
32
|
+
custom_props = []
|
33
|
+
props = attributes.keys
|
34
|
+
PropertyDefinition.find(:all).each do |prop|
|
35
|
+
custom_props << {prop.name => prop.column_name} if(props.include?(prop.column_name))
|
36
|
+
end
|
37
|
+
custom_props
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Mingle4r
|
2
|
+
module Helpers
|
3
|
+
def Helpers.fast_token
|
4
|
+
values = [
|
5
|
+
rand(0x0010000),
|
6
|
+
rand(0x0010000),
|
7
|
+
rand(0x0010000),
|
8
|
+
rand(0x0010000),
|
9
|
+
rand(0x0010000),
|
10
|
+
rand(0x1000000),
|
11
|
+
rand(0x1000000),
|
12
|
+
]
|
13
|
+
"%04x%04x%04x%04x%04x%06x%06x" % values
|
14
|
+
end
|
15
|
+
|
16
|
+
def Helpers.encode2html(string)
|
17
|
+
html_char_map = {
|
18
|
+
'[' => '%5B', ']' => '%5D',
|
19
|
+
'(' => '%28', ')' => '%29',
|
20
|
+
',' => '%2C', ' ' => '%20',
|
21
|
+
'=' => '%3D', '\'' => '%27',
|
22
|
+
'<' => '%3C', '>' => '%3E',
|
23
|
+
}
|
24
|
+
|
25
|
+
string.strip! if string
|
26
|
+
encoded_string = ''
|
27
|
+
string.each_char do |char|
|
28
|
+
encoded_string << (html_char_map[char] || char)
|
29
|
+
end
|
30
|
+
encoded_string
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Mingle4r
|
2
|
+
class MingleClient
|
3
|
+
attr_reader :site, :user, :password, :proj_id
|
4
|
+
|
5
|
+
def initialize(site, user, password, proj_id = nil)
|
6
|
+
@site = site
|
7
|
+
@user = user
|
8
|
+
@password = password
|
9
|
+
@proj_id = proj_id
|
10
|
+
set_resource_attributes()
|
11
|
+
end
|
12
|
+
|
13
|
+
def site=(site)
|
14
|
+
if site != self.site
|
15
|
+
@site = site
|
16
|
+
uri = URI.parse(site)
|
17
|
+
@user = URI.decode(uri.user) if(uri.user)
|
18
|
+
@password = URI.decode(uri.password) if(uri.password)
|
19
|
+
set_resource_attributes()
|
20
|
+
end
|
21
|
+
@site
|
22
|
+
end
|
23
|
+
|
24
|
+
def user=(user)
|
25
|
+
if user != self.user
|
26
|
+
@user = user
|
27
|
+
set_resource_attributes()
|
28
|
+
end
|
29
|
+
@user
|
30
|
+
end
|
31
|
+
|
32
|
+
def password=(password)
|
33
|
+
if password != self.password
|
34
|
+
@password = password
|
35
|
+
set_resource_attributes()
|
36
|
+
end
|
37
|
+
@password
|
38
|
+
end
|
39
|
+
|
40
|
+
def proj_id=(proj_id)
|
41
|
+
if proj_id != @proj_id
|
42
|
+
@proj_id = proj_id
|
43
|
+
set_resource_attributes()
|
44
|
+
end
|
45
|
+
@proj_id
|
46
|
+
end
|
47
|
+
|
48
|
+
def valid_credentials?
|
49
|
+
Project.site = site
|
50
|
+
Project.user = user
|
51
|
+
Project.password = password
|
52
|
+
begin
|
53
|
+
Project.find(:all)
|
54
|
+
true
|
55
|
+
rescue Exception => e
|
56
|
+
e.message
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def project
|
61
|
+
raise 'proj_id attribute not set' unless @proj_id
|
62
|
+
@project = Mingle4r::Project.find(@proj_id) unless(@project && (@proj_id == @project.identifier))
|
63
|
+
@project
|
64
|
+
end
|
65
|
+
|
66
|
+
def projects
|
67
|
+
Mingle4r::Project.find(:all)
|
68
|
+
end
|
69
|
+
|
70
|
+
def cards
|
71
|
+
raise 'proj_id attribute not set' unless @proj_id
|
72
|
+
@project = Mingle4r::Project.find(@proj_id) unless(@project && (@proj_id == @project.identifier))
|
73
|
+
@project.cards
|
74
|
+
end
|
75
|
+
|
76
|
+
def users
|
77
|
+
Mingle4r::User.find(:all)
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
def set_resource_attributes
|
82
|
+
set_project_attributes
|
83
|
+
set_user_attributes
|
84
|
+
end
|
85
|
+
|
86
|
+
def set_project_attributes
|
87
|
+
Project.site = @site
|
88
|
+
Project.user = @user
|
89
|
+
Project.password = @password
|
90
|
+
end
|
91
|
+
|
92
|
+
# def set_property_definition_attributes
|
93
|
+
# raise 'Project Id (proj_id attribute) not given.' unless @proj_id
|
94
|
+
# properties_site = File.join(@site.to_s, "projects/#{@proj_id}")
|
95
|
+
# PropertyDefinition.site = properties_site
|
96
|
+
# PropertyDefinition.user = @user
|
97
|
+
# PropertyDefinition.password = @password
|
98
|
+
# end
|
99
|
+
|
100
|
+
def set_user_attributes
|
101
|
+
User.site = @site
|
102
|
+
User.user = user
|
103
|
+
User.password = @password
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Mingle4r
|
2
|
+
class Project
|
3
|
+
module InstanceMethods
|
4
|
+
# returns the cards for the project. To hit the resource server without returning
|
5
|
+
# cached results pass true as an argument.
|
6
|
+
def cards(refresh = false)
|
7
|
+
return @cards if(!refresh && @cards_cached)
|
8
|
+
cards_site = File.join(self.class.site.to_s, "projects/#{self.identifier()}")
|
9
|
+
Mingle4r::Card.site = cards_site
|
10
|
+
Mingle4r::Card.user = self.class.user
|
11
|
+
Mingle4r::Card.password = self.class.password
|
12
|
+
card_class = Mingle4r::Card.send(:create_resource_class)
|
13
|
+
@cards = card_class.find_without_pagination(:all)
|
14
|
+
@cards_cached = true
|
15
|
+
@cards
|
16
|
+
end
|
17
|
+
|
18
|
+
# returns the users for the project. To hit the resource server without returning
|
19
|
+
# cached results pass true as an argument.
|
20
|
+
def users(refresh = false)
|
21
|
+
return @users if(!refresh && @users_cached)
|
22
|
+
users_site = File.join(self.class.site.to_s, "projects/#{self.identifier()}")
|
23
|
+
Mingle4r::User.site = users_site
|
24
|
+
Mingle4r::User.user = self.class.user
|
25
|
+
Mingle4r::User.password = self.class.password
|
26
|
+
Mingle4r::User.element_name = nil # reset
|
27
|
+
user_class = Mingle4r::User.send(:create_resource_class)
|
28
|
+
@users = user_class.find(:all)
|
29
|
+
@users_cached = true
|
30
|
+
@users
|
31
|
+
end
|
32
|
+
|
33
|
+
# returns the wikis for the project. To hit the resource server without returning
|
34
|
+
# cached results pass true as an argument.
|
35
|
+
def wikis(refresh = false)
|
36
|
+
return @wikis if(!refresh && @wikis_cached)
|
37
|
+
wiki_site = File.join(self.class.site.to_s, "projects/#{self.identifier()}")
|
38
|
+
Mingle4r::Wiki.site = wiki_site
|
39
|
+
Mingle4r::Wiki.user = self.class.user
|
40
|
+
Mingle4r::Wiki.password = self.class.password
|
41
|
+
wiki_class = Mingle4r::Wiki.send(:create_resource_class)
|
42
|
+
@wikis = wiki_class.find(:all)
|
43
|
+
@wikis_cached = true
|
44
|
+
@wikis
|
45
|
+
end
|
46
|
+
|
47
|
+
# returns the property definitions for the project. To hit the resource server
|
48
|
+
# pass true as an argument
|
49
|
+
def property_definitions(refresh = false)
|
50
|
+
return @prop_definitions if(!refresh && @prop_definitions_cached)
|
51
|
+
properties_site = File.join(@site.to_s, "projects/#{self.identifier}")
|
52
|
+
PropertyDefinition.site = properties_site
|
53
|
+
PropertyDefinition.user = @user
|
54
|
+
PropertyDefinition.password = @password
|
55
|
+
prop_defn_class = Mingle4r::PropertyDefinition.send(:create_resource_class)
|
56
|
+
@prop_definitions = prop_defn_class.find(:all)
|
57
|
+
@prop_definitions_cached = true
|
58
|
+
@prop_definitions
|
59
|
+
end
|
60
|
+
end # module InstanceMethods
|
61
|
+
|
62
|
+
extend Mingle4r::CommonClassMethods
|
63
|
+
end # class Project
|
64
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Mingle4r
|
2
|
+
class PropertyDefinition
|
3
|
+
# module InstanceMethods
|
4
|
+
# end
|
5
|
+
#
|
6
|
+
# module ClassMethods
|
7
|
+
# end
|
8
|
+
#
|
9
|
+
extend Mingle4r::CommonClassMethods
|
10
|
+
|
11
|
+
self.element_name = 'record'
|
12
|
+
|
13
|
+
def self.column_name_for(prop_name)
|
14
|
+
property_def = @resource_class.find(:all).detect { |prop| prop.name == prop_name }
|
15
|
+
property_def ? property_def.column_name : nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe Mingle4r::Card::Attachment do
|
4
|
+
it "should be able to create a class inherited from ActiveResource::Base" do
|
5
|
+
attachment_class = mock(Object)
|
6
|
+
|
7
|
+
attachment_class.should_receive(:site=).any_number_of_times
|
8
|
+
attachment_class.should_receive(:user=).any_number_of_times
|
9
|
+
attachment_class.should_receive(:password=).any_number_of_times
|
10
|
+
attachment_class.should_receive(:collection_name=).any_number_of_times
|
11
|
+
attachment_class.should_receive(:element_name=).any_number_of_times
|
12
|
+
attachment_class.should_receive(:include).any_number_of_times
|
13
|
+
Class.should_receive(:new).with(MingleResource).any_number_of_times.and_return(attachment_class)
|
14
|
+
|
15
|
+
Mingle4r::Card::Attachment.site = ''
|
16
|
+
Mingle4r::Card::Attachment.user = ''
|
17
|
+
Mingle4r::Card::Attachment.password = ''
|
18
|
+
|
19
|
+
Mingle4r::Card::Attachment.send(:create_resource_class).should == attachment_class
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should be able to download file to a location" do
|
23
|
+
Mingle4r::Card::Attachment.site = 'http://localhost/test'
|
24
|
+
Mingle4r::Card::Attachment.user = 'test'
|
25
|
+
Mingle4r::Card::Attachment.password = 'password'
|
26
|
+
|
27
|
+
attachment_obj = Mingle4r::Card::Attachment.new
|
28
|
+
attachment_obj.should_receive(:url).and_return('/attachment')
|
29
|
+
attachment_obj.should_receive(:file_name).and_return('attach')
|
30
|
+
|
31
|
+
request_obj = mock(Object)
|
32
|
+
request_obj.should_receive(:basic_auth)
|
33
|
+
|
34
|
+
response_obj = mock(Object)
|
35
|
+
response_obj.should_receive(:body).and_return('test text')
|
36
|
+
|
37
|
+
Net::HTTP::Get.should_receive(:new).and_return(request_obj)
|
38
|
+
Net::HTTP.should_receive(:start).and_return(response_obj)
|
39
|
+
|
40
|
+
|
41
|
+
attachment_obj.download()
|
42
|
+
|
43
|
+
File.exist?('attach').should == true
|
44
|
+
file_contents = IO.read('attach')
|
45
|
+
file_contents.should == 'test text'
|
46
|
+
File.delete('attach')
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Mingle4r::Card do
|
4
|
+
it "should be able to call active resource find method with proper params" do
|
5
|
+
Mingle4r::Card.site = 'http://localhost/projects/test'
|
6
|
+
Mingle4r::Card.user = 'user'
|
7
|
+
Mingle4r::Card.password = 'password'
|
8
|
+
|
9
|
+
card_class = Mingle4r::Card.send(:create_resource_class)
|
10
|
+
card_class.should_receive(:find).with(:all, :params => {:page => 'all'})
|
11
|
+
card_class.find_without_pagination(:all)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should set attributes in attachment class properly" do
|
15
|
+
Mingle4r::Card.site = 'http://localhost/projects/test'
|
16
|
+
Mingle4r::Card.user = 'user'
|
17
|
+
Mingle4r::Card.password = 'password'
|
18
|
+
|
19
|
+
card_obj = Mingle4r::Card.new
|
20
|
+
card_obj.should_receive(:number).and_return(10)
|
21
|
+
|
22
|
+
attachment_class_mock = mock(Class)
|
23
|
+
Mingle4r::Card::Attachment.should_receive(:create_resource_class).any_number_of_times.and_return(attachment_class_mock)
|
24
|
+
|
25
|
+
attachment_class_mock.should_receive(:find)
|
26
|
+
card_obj.attachments
|
27
|
+
|
28
|
+
Mingle4r::Card::Attachment.site.should == 'http://localhost/projects/test/cards/10'
|
29
|
+
Mingle4r::Card::Attachment.user.should == 'user'
|
30
|
+
Mingle4r::Card::Attachment.password.should == 'password'
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should return the http body boundary" do
|
34
|
+
Mingle4r::Card.site = 'http://localhost/projects/test'
|
35
|
+
Mingle4r::Card.user = 'user'
|
36
|
+
Mingle4r::Card.password = 'password'
|
37
|
+
|
38
|
+
Mingle4r::Card.new.send(:boundary).should == '----------XnJLe9ZIbbGUYtzPQJ16u1'
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
class DummyClass
|
4
|
+
module InstanceMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
# module ClassMethods
|
8
|
+
# end
|
9
|
+
extend Mingle4r::CommonClassMethods
|
10
|
+
end
|
11
|
+
|
12
|
+
describe DummyClass do
|
13
|
+
it "should be able to set the site properly" do
|
14
|
+
url = 'http://localhost/test'
|
15
|
+
DummyClass.site = url
|
16
|
+
DummyClass.site.should == url
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should be able to set the user properly" do
|
20
|
+
user = 'testuser'
|
21
|
+
DummyClass.user = user
|
22
|
+
DummyClass.user.should == user
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should be able to set the password properly" do
|
26
|
+
password = 'password'
|
27
|
+
DummyClass.password = password
|
28
|
+
DummyClass.password.should == password
|
29
|
+
end
|
30
|
+
|
31
|
+
xit "should understand that the attributes have been set" do
|
32
|
+
DummyClass.site = 'http://localhost:8080'
|
33
|
+
DummyClass.user = 'test'
|
34
|
+
DummyClass.password = 'password'
|
35
|
+
assert DummyClass.all_attributes_set?
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should be able to create an instance" do
|
39
|
+
dummy_obj = DummyClass.new
|
40
|
+
dummy_obj.should_not == nil
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should be able to create a class inherited from ActiveResource::Base" do
|
44
|
+
dummy_obj = DummyClass.new
|
45
|
+
dummy_obj.class.superclass.should == ActiveResource::Base
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should create same class when site is not changed" do
|
49
|
+
class DummyClass
|
50
|
+
class << self
|
51
|
+
attr_reader :resource_class
|
52
|
+
end
|
53
|
+
end
|
54
|
+
site = 'http://localhost/foo'
|
55
|
+
DummyClass.site = site
|
56
|
+
DummyClass.user = 'test'
|
57
|
+
DummyClass.password = 'password'
|
58
|
+
class1 = DummyClass.resource_class
|
59
|
+
DummyClass.site = site
|
60
|
+
class2 = DummyClass.resource_class
|
61
|
+
class1.should == class2
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should create different classes when site is changed" do
|
65
|
+
class DummyClass
|
66
|
+
class << self
|
67
|
+
attr_reader :resource_class
|
68
|
+
end
|
69
|
+
end
|
70
|
+
site1 = 'http://localhost/foo'
|
71
|
+
site2 = 'http://localhost/bar'
|
72
|
+
DummyClass.site = site1
|
73
|
+
DummyClass.user = 'test'
|
74
|
+
DummyClass.password = 'password'
|
75
|
+
class1 = DummyClass.resource_class
|
76
|
+
DummyClass.site = site2
|
77
|
+
class2 = DummyClass.resource_class
|
78
|
+
class1.should_not == class2
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should be able to find the instance methods module in the class" do
|
82
|
+
DummyClass.send(:instance_methods_module_name).should == 'InstanceMethods'
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should not be able to find class methods module in the class" do
|
86
|
+
DummyClass.send(:class_methods_module_name).should be_nil
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should return the class name only without nesting of namespaces" do
|
90
|
+
DummyClass.send(:class_name).should == 'DummyClass'
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should call find with proper params" do
|
94
|
+
# open access to @resource var
|
95
|
+
class << DummyClass
|
96
|
+
attr_writer :resource_class
|
97
|
+
end
|
98
|
+
|
99
|
+
mock_class = mock(Class)
|
100
|
+
DummyClass.resource_class = mock_class
|
101
|
+
mock_class.should_receive(:find).with(:all, :from => 'http://localhost/test', :params => {:foo => 'bar'})
|
102
|
+
DummyClass.find(:all, :from => 'http://localhost/test', :params => {:foo => 'bar'})
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Mingle4r::Helpers do
|
4
|
+
it "should return a token" do
|
5
|
+
assert Mingle4r::Helpers::fast_token
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should not return the same token" do
|
9
|
+
token1 = Mingle4r::Helpers::fast_token
|
10
|
+
token2 = Mingle4r::Helpers::fast_token
|
11
|
+
assert_not_equal(token1, token2)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should return a string in proper html format" do
|
15
|
+
string = 'Hello(whosoever) world []'
|
16
|
+
html_result = Mingle4r::Helpers::encode2html(string)
|
17
|
+
html_expected = 'Hello%28whosoever%29%20world%20%5B%5D'
|
18
|
+
html_result.should == html_expected
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Mingle4r::Project do
|
4
|
+
it "should return the set the Card class attributes properly" do
|
5
|
+
Mingle4r::Project.site = 'http://localhost'
|
6
|
+
Mingle4r::Project.user = 'test'
|
7
|
+
Mingle4r::Project.password = 'password'
|
8
|
+
|
9
|
+
proj = Mingle4r::Project.new(:identifier => 'test')
|
10
|
+
card_class_mock = mock(Class)
|
11
|
+
Mingle4r::Card.should_receive(:create_resource_class).any_number_of_times.and_return(card_class_mock)
|
12
|
+
card_class_mock.should_receive(:find_without_pagination).with(:all)
|
13
|
+
|
14
|
+
proj.cards
|
15
|
+
|
16
|
+
Mingle4r::Card.site.should == 'http://localhost/projects/test'
|
17
|
+
Mingle4r::Card.user.should == 'test'
|
18
|
+
Mingle4r::Card.password.should == 'password'
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
describe Mingle4r::PropertyDefinition do
|
5
|
+
before(:all) do
|
6
|
+
Mingle4r::PropertyDefinition.site = 'http://localhost:8080/projects/test'
|
7
|
+
Mingle4r::PropertyDefinition.user = 'test'
|
8
|
+
Mingle4r::PropertyDefinition.password = 'secret'
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should return the element name properly" do
|
12
|
+
Mingle4r::PropertyDefinition::element_name.should == 'record'
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should return the property value" do
|
16
|
+
class Mingle4r::PropertyDefinition
|
17
|
+
class << self
|
18
|
+
attr_accessor :resource_class
|
19
|
+
end
|
20
|
+
end
|
21
|
+
resource_class = mock(Class)
|
22
|
+
property_1 = { :name => 'Test Property', :column_name => 'test_property_name' }
|
23
|
+
property_2 = { :name => 'Added in Iteration number', :column_name => 'added_in_iteration_number'}
|
24
|
+
find_results = [OpenStruct.new(property_1), OpenStruct.new(property_2)]
|
25
|
+
Mingle4r::PropertyDefinition.resource_class = resource_class
|
26
|
+
resource_class.should_receive(:find).with(:all).any_number_of_times.and_return(find_results)
|
27
|
+
Mingle4r::PropertyDefinition.column_name_for('Test Property').should == 'test_property_name'
|
28
|
+
Mingle4r::PropertyDefinition.column_name_for('Added in Iteration number').should == 'added_in_iteration_number'
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe Mingle4r::Wiki do
|
4
|
+
it "should return the collection name properly" do
|
5
|
+
Mingle4r::Wiki::collection_name.should == 'wiki'
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should return the element name properly" do
|
9
|
+
Mingle4r::Wiki::element_name.should == 'page'
|
10
|
+
end
|
11
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require '../../lib/mingle4r'
|
2
|
+
|
3
|
+
|
4
|
+
class Mingle4r::Project
|
5
|
+
class << self
|
6
|
+
attr_reader :resource_class
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
m_c = Mingle4r::MingleClient.new('http://localhost:9090', 'testuser', 'testuser', 'api_test')
|
11
|
+
|
12
|
+
|
13
|
+
proj = m_c.project
|
14
|
+
puts proj.users.size
|
15
|
+
cards = m_c.cards
|
16
|
+
card = cards[2]
|
17
|
+
puts '------------------------------'
|
18
|
+
puts Mingle4r::PropertyDefinition.site
|
19
|
+
puts Mingle4r::PropertyDefinition.user
|
20
|
+
puts Mingle4r::PropertyDefinition.password
|
21
|
+
puts Mingle4r::PropertyDefinition.new.class.collection_path
|
22
|
+
|
23
|
+
puts card.property_value('Name')
|
24
|
+
puts '||||||||||||||||||||||||||||||'
|
25
|
+
puts card.custom_properties
|
26
|
+
puts card.number
|
27
|
+
puts card.description
|
28
|
+
# card.description = 'test'
|
29
|
+
# card.save
|
30
|
+
attachment = card.attachments[0]
|
31
|
+
# puts attachment.url
|
32
|
+
|
33
|
+
# delete attachments
|
34
|
+
Mingle4r::Card::Attachment.site = 'http://localhost:9090/projects/api_test/cards/18'
|
35
|
+
Mingle4r::Card::Attachment.user = 'testuser'
|
36
|
+
Mingle4r::Card::Attachment.password = 'testuser'
|
37
|
+
|
38
|
+
attachment = Mingle4r::Card::Attachment.find(:all)[0]
|
39
|
+
# attachment.delete
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require File.dirname(__FILE__) + '/../../lib/mingle4r'
|
3
|
+
|
4
|
+
Mingle4r::Card.site = 'http://localhost:9090/projects/api_test'
|
5
|
+
Mingle4r::Card.user = 'testuser'
|
6
|
+
Mingle4r::Card.password = 'testuser'
|
7
|
+
card = Mingle4r::Card.find(18)
|
8
|
+
|
9
|
+
puts card.add_comment('testingcomment')
|
@@ -0,0 +1,7 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require File.dirname(__FILE__) + '/../../lib/mingle4r'
|
3
|
+
|
4
|
+
Mingle4r::Card.site = 'http://localhost:9090/projects/api_test'
|
5
|
+
Mingle4r::Card.user = 'testuser'
|
6
|
+
Mingle4r::Card.password = 'testuser'
|
7
|
+
puts (Mingle4r::Card.apply_filter('Type IS Defect')).size
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require File.dirname(__FILE__) + '/../../lib/mingle4r'
|
3
|
+
|
4
|
+
Mingle4r::Card.site = 'http://localhost:9090/projects/api_test'
|
5
|
+
Mingle4r::Card.user = 'testuser'
|
6
|
+
Mingle4r::Card.password = 'testuser'
|
7
|
+
card = Mingle4r::Card.find(21)
|
8
|
+
|
9
|
+
card.execute_transition(:transition_name => 'Close Defect')
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require File.dirname(__FILE__) + '/../../lib/mingle4r'
|
3
|
+
|
4
|
+
Mingle4r::User.site = 'http://localhost:9090/projects/api_test'
|
5
|
+
Mingle4r::User.user = 'testuser'
|
6
|
+
Mingle4r::User.password = 'testuser'
|
7
|
+
|
8
|
+
users = Mingle4r::User.find(:all)
|
9
|
+
|
10
|
+
puts users[0].user
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require File.dirname(__FILE__) + '/../../lib/mingle4r'
|
3
|
+
|
4
|
+
Mingle4r::Card.site = 'http://localhost:9090/projects/api_test'
|
5
|
+
Mingle4r::Card.user = 'testuser'
|
6
|
+
Mingle4r::Card.password = 'testuser'
|
7
|
+
|
8
|
+
card = Mingle4r::Card.find(26)
|
9
|
+
puts card.upload_attachment(File.join(File.dirname(__FILE__), '/../../README'))
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arusarka-mingle4r
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- asur
|
@@ -31,8 +31,40 @@ extensions: []
|
|
31
31
|
extra_rdoc_files:
|
32
32
|
- README
|
33
33
|
files:
|
34
|
+
- lib/mingle4r/card.rb
|
35
|
+
- lib/mingle4r/card/attachment.rb
|
36
|
+
- lib/mingle4r/common_class_methods.rb
|
37
|
+
- lib/mingle4r/common_dyn_class_instance_methods.rb
|
38
|
+
- lib/mingle4r/helpers.rb
|
39
|
+
- lib/mingle4r/mingle_client.rb
|
40
|
+
- lib/mingle4r/project.rb
|
41
|
+
- lib/mingle4r/property_definition.rb
|
42
|
+
- lib/mingle4r/user.rb
|
43
|
+
- lib/mingle4r/version.rb
|
44
|
+
- lib/mingle4r/wiki.rb
|
45
|
+
- lib/mingle4r.rb
|
46
|
+
- lib/mingle_resource.rb
|
47
|
+
- spec/mingle4r/card/attachment_spec.rb
|
48
|
+
- spec/mingle4r/card_spec.rb
|
49
|
+
- spec/mingle4r/common_class_methods_spec.rb
|
50
|
+
- spec/mingle4r/helpers_spec.rb
|
51
|
+
- spec/mingle4r/project_spec.rb
|
52
|
+
- spec/mingle4r/property_definition_spec.rb
|
53
|
+
- spec/mingle4r/version_spec.rb
|
54
|
+
- spec/mingle4r/wiki_spec.rb
|
55
|
+
- spec/mingle4r_spec.rb
|
56
|
+
- spec/spec_helper.rb
|
57
|
+
- test/integration/test.rb
|
58
|
+
- test/integration/test_adding_comment.rb
|
59
|
+
- test/integration/test_card_filter.rb
|
60
|
+
- test/integration/test_card_transition.rb
|
61
|
+
- test/integration/test_getting_users.rb
|
62
|
+
- test/integration/test_uploading_attachment.rb
|
63
|
+
- test/integration/test_wiki.rb
|
64
|
+
- MIT-LICENSE
|
65
|
+
- Rakefile
|
34
66
|
- README
|
35
|
-
-
|
67
|
+
- TODO.txt
|
36
68
|
has_rdoc: false
|
37
69
|
homepage: http://github.com/arusarka/mingle4r/
|
38
70
|
post_install_message:
|
data/History.txt
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
0.2.2
|
2
|
-
-----
|
3
|
-
|
4
|
-
* added add_comment to card class. allows adding comment to a card
|
5
|
-
|
6
|
-
0.2.1
|
7
|
-
-----
|
8
|
-
|
9
|
-
* added option to relationship methods(e.g. - cards, users, attachments) to return cached or
|
10
|
-
updated results
|
11
|
-
* property_definitions is a relationship method of project instead of mingle client.
|
12
|
-
|
13
|
-
0.2.0
|
14
|
-
-----
|
15
|
-
|
16
|
-
* added class method apply_filter to Card class. allows an MQL filter
|
17
|
-
* added instance method execute_transition to Card class. allows to execute a transition on a card.
|
18
|
-
|
19
|
-
0.1.6
|
20
|
-
-----
|
21
|
-
|
22
|
-
* added instance method at_version to Card class. gets the particular version for the card
|
23
|
-
|
24
|
-
0.1.5
|
25
|
-
-----
|
26
|
-
|
27
|
-
* Rest Api's added - wiki
|
28
|
-
|
29
|
-
0.0.1
|
30
|
-
-----
|
31
|
-
|
32
|
-
* Rest Api's - Card, Project, User, Attachment, Property Definition
|
33
|
-
* Mingle Client - supports getting cards, project etc.
|