mingle4r 0.3.0

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.
@@ -0,0 +1,220 @@
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
+ @resource_class.find(scope, options)
165
+ end
166
+
167
+ private
168
+ # creates an active resource class dynamically. All the attributes are set automatically. Avoid calling
169
+ # this method directly
170
+ def create_resource_class
171
+ # raise exceptions if site is not set
172
+ raise "Please set the site for #{self} class." unless(self.site)
173
+
174
+ created_class = Class.new(MingleResource)
175
+
176
+ # set the resource options
177
+ created_class.site = self.site
178
+ created_class.user = self.user
179
+ created_class.password = self.password
180
+ created_class.collection_name = self.collection_name
181
+ created_class.element_name = self.element_name
182
+
183
+ # created_class_name = "#{self}::#{class_name}#{Mingle4r::Helpers.fast_token()}"
184
+ created_class_name = class_name + Mingle4r::Helpers.fast_token()
185
+ created_class = self.const_set(created_class_name, created_class)
186
+ # eval "#{created_class_name} = created_class"
187
+
188
+ # includes a module called InstanceMethods in the class created dynamically
189
+ # if it is defined inside the wrapper class
190
+ inst_meth_mod_name = instance_methods_module_name()
191
+ created_class.send(:include, self.const_get(inst_meth_mod_name.to_sym)) if inst_meth_mod_name
192
+ created_class.send(:include, Mingle4r::CommonDynClassInstanceMethods)
193
+
194
+ # extends the class created dynamically with a module called ClassMethods if
195
+ # it is defined inside the wrapper class
196
+ class_meth_mod_name = class_methods_module_name()
197
+ created_class.extend(self.const_get(class_meth_mod_name)) if class_meth_mod_name
198
+
199
+ created_class
200
+ end
201
+
202
+ def class_name
203
+ self.name.split('::')[-1]
204
+ end
205
+
206
+ def instance_methods_module_name
207
+ inst_meth_mod_name = 'InstanceMethods'
208
+ self.constants.detect { |const| const.split('::')[-1] =~ /#{inst_meth_mod_name}/ }
209
+ end
210
+
211
+ def class_methods_module_name
212
+ class_meth_mod_name = 'ClassMethods'
213
+ self.constants.detect { |const| const.split('::')[-1] =~ /#{class_meth_mod_name}/ }
214
+ end
215
+
216
+ def method_missing(meth_id, *args, &block)
217
+ @resource_class.send(meth_id.to_sym, *args, &block)
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,5 @@
1
+ module Mingle4r
2
+ # common dynamic class instance methods
3
+ module CommonDynClassInstanceMethods
4
+ end
5
+ 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,91 @@
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_class = @api.project_class
50
+ project_class.site = @api.base_url
51
+ project_class.user = user
52
+ project_class.password = password
53
+ begin
54
+ project_class.find(:all)
55
+ true
56
+ rescue Exception => e
57
+ e.message
58
+ end
59
+ end
60
+
61
+ def project
62
+ raise 'proj_id attribute not set' unless @proj_id
63
+ @project = @api.project_class.find(@proj_id) unless(@project && (@proj_id == @project.identifier))
64
+ @project
65
+ end
66
+
67
+ def projects
68
+ @api.project_class.find(:all)
69
+ end
70
+
71
+ def users
72
+ @api.user_class.find(:all)
73
+ end
74
+
75
+ private
76
+ def set_resource_attributes
77
+ @api = API.create(@site)
78
+ set_attributes(@api.project_class)
79
+ set_attributes(@api.user_class)
80
+ end
81
+
82
+ def set_attributes(klass)
83
+ klass.site = @api.base_url
84
+ klass.user = @user
85
+ klass.password = @password
86
+ end
87
+ end
88
+ end
89
+
90
+ # alias for the lazy ones
91
+ MingleClient = Mingle4r::MingleClient
@@ -0,0 +1,11 @@
1
+ module Mingle4r
2
+ module Version
3
+ Major = '0'
4
+ Minor = '3'
5
+ Tiny = '0'
6
+
7
+ def self.to_s
8
+ Major + '.' + Minor + '.' + Tiny
9
+ end
10
+ end
11
+ end
data/lib/mingle4r.rb ADDED
@@ -0,0 +1,41 @@
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/mingle_client'
19
+ require 'mingle4r/api'
20
+
21
+ # Version 1 of api
22
+ require 'mingle4r/api/v1'
23
+ require 'mingle4r/api/v1/card'
24
+ require 'mingle4r/api/v1/card/attachment'
25
+ require 'mingle4r/api/v1/project'
26
+ require 'mingle4r/api/v1/property_definition'
27
+ require 'mingle4r/api/v1/transition_execution'
28
+ require 'mingle4r/api/v1/user'
29
+ require 'mingle4r/api/v1/wiki'
30
+
31
+ # version 2 of api
32
+ require 'mingle4r/api/v2'
33
+ require 'mingle4r/api/v2/card'
34
+ require 'mingle4r/api/v2/card/attachment'
35
+ require 'mingle4r/api/v2/card/comment'
36
+ require 'mingle4r/api/v2/card/transition'
37
+ require 'mingle4r/api/v2/murmur'
38
+ require 'mingle4r/api/v2/project'
39
+ require 'mingle4r/api/v2/property_definition'
40
+ require 'mingle4r/api/v2/user'
41
+ require 'mingle4r/api/v2/wiki'
@@ -0,0 +1,2 @@
1
+ # to avoid writing ActiveResource::Base
2
+ MingleResource = ActiveResource::Base
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mingle4r
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - asur
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-12-07 00:00:00 +05:30
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activeresource
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description: " A connector wrapper for connecting to Mingle(http://studios.thoughtworks.com/mingle-agile-project-management).\n It uses active resource to handle the restful connections to Mingle. Makes the job of connecting to Mingle a \n lot easier. Also since it uses lazy evaluation, resources are fetched only when they are requested.\n"
26
+ email: arusarka@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README
33
+ files:
34
+ - lib/mingle4r.rb
35
+ - lib/mingle_resource.rb
36
+ - lib/mingle4r/api.rb
37
+ - lib/mingle4r/common_class_methods.rb
38
+ - lib/mingle4r/common_dyn_class_instance_methods.rb
39
+ - lib/mingle4r/helpers.rb
40
+ - lib/mingle4r/mingle_client.rb
41
+ - lib/mingle4r/version.rb
42
+ - lib/mingle4r/api/v1.rb
43
+ - lib/mingle4r/api/v1/card.rb
44
+ - lib/mingle4r/api/v1/card/attachment.rb
45
+ - lib/mingle4r/api/v1/project.rb
46
+ - lib/mingle4r/api/v1/property_definition.rb
47
+ - lib/mingle4r/api/v1/transition_execution.rb
48
+ - lib/mingle4r/api/v1/user.rb
49
+ - lib/mingle4r/api/v1/wiki.rb
50
+ - lib/mingle4r/api/v2.rb
51
+ - lib/mingle4r/api/v2/card.rb
52
+ - lib/mingle4r/api/v2/card/attachment.rb
53
+ - lib/mingle4r/api/v2/card/comment.rb
54
+ - lib/mingle4r/api/v2/card/transition.rb
55
+ - lib/mingle4r/api/v2/murmur.rb
56
+ - lib/mingle4r/api/v2/project.rb
57
+ - lib/mingle4r/api/v2/property_definition.rb
58
+ - lib/mingle4r/api/v2/user.rb
59
+ - lib/mingle4r/api/v2/wiki.rb
60
+ - MIT-LICENSE
61
+ - History.txt
62
+ - README
63
+ - TODO.txt
64
+ has_rdoc: true
65
+ homepage: http://github.com/arusarka/mingle4r/
66
+ licenses: []
67
+
68
+ post_install_message:
69
+ rdoc_options: []
70
+
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: "0"
78
+ version:
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: "0"
84
+ version:
85
+ requirements: []
86
+
87
+ rubyforge_project:
88
+ rubygems_version: 1.3.5
89
+ signing_key:
90
+ specification_version: 3
91
+ summary: Mingle connector using active resource
92
+ test_files: []
93
+