test_redmine_vz 0.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/Gemfile +4 -0
  4. data/README.md +71 -0
  5. data/Rakefile +20 -0
  6. data/config/currency_iso.json +2532 -0
  7. data/doc/CHANGELOG +55 -0
  8. data/doc/LICENSE.txt +339 -0
  9. data/lib/redmine_crm.rb +67 -0
  10. data/lib/redmine_crm/currency.rb +439 -0
  11. data/lib/redmine_crm/currency/formatting.rb +227 -0
  12. data/lib/redmine_crm/currency/heuristics.rb +151 -0
  13. data/lib/redmine_crm/currency/loader.rb +24 -0
  14. data/lib/redmine_crm/helpers/tags_helper.rb +15 -0
  15. data/lib/redmine_crm/helpers/vote_helper.rb +38 -0
  16. data/lib/redmine_crm/liquid/drops/issues_drop.rb +61 -0
  17. data/lib/redmine_crm/liquid/drops/news_drop.rb +45 -0
  18. data/lib/redmine_crm/liquid/drops/projects_drop.rb +78 -0
  19. data/lib/redmine_crm/liquid/drops/users_drop.rb +59 -0
  20. data/lib/redmine_crm/liquid/filters.rb +85 -0
  21. data/lib/redmine_crm/money_helper.rb +67 -0
  22. data/lib/redmine_crm/rcrm_acts_as_taggable.rb +342 -0
  23. data/lib/redmine_crm/rcrm_acts_as_viewed.rb +287 -0
  24. data/lib/redmine_crm/rcrm_acts_as_votable.rb +79 -0
  25. data/lib/redmine_crm/rcrm_acts_as_voter.rb +27 -0
  26. data/lib/redmine_crm/tag.rb +81 -0
  27. data/lib/redmine_crm/tag_list.rb +112 -0
  28. data/lib/redmine_crm/tagging.rb +20 -0
  29. data/lib/redmine_crm/version.rb +3 -0
  30. data/lib/redmine_crm/votable.rb +334 -0
  31. data/lib/redmine_crm/vote.rb +30 -0
  32. data/lib/redmine_crm/voter.rb +136 -0
  33. data/redmine_crm.gemspec +22 -0
  34. data/test/acts_as_taggable_test.rb +384 -0
  35. data/test/currency_test.rb +292 -0
  36. data/test/database.yml +17 -0
  37. data/test/fixtures/issue.rb +14 -0
  38. data/test/fixtures/issues.yml +12 -0
  39. data/test/fixtures/taggings.yml +32 -0
  40. data/test/fixtures/tags.yml +11 -0
  41. data/test/fixtures/user.rb +7 -0
  42. data/test/fixtures/users.yml +5 -0
  43. data/test/fixtures/votable_caches.yml +2 -0
  44. data/test/fixtures/votables.yml +4 -0
  45. data/test/fixtures/vote_classes.rb +54 -0
  46. data/test/fixtures/voters.yml +6 -0
  47. data/test/liquid_test.rb +80 -0
  48. data/test/money_helper_test.rb +12 -0
  49. data/test/schema.rb +100 -0
  50. data/test/tag_test.rb +63 -0
  51. data/test/tagging_test.rb +14 -0
  52. data/test/tags_helper_test.rb +29 -0
  53. data/test/test_helper.rb +118 -0
  54. data/test/viewed_test.rb +45 -0
  55. data/test/votable_model_test.rb +478 -0
  56. data/test/votable_test.rb +17 -0
  57. data/test/vote_helper_test.rb +28 -0
  58. data/test/voter_model_test.rb +296 -0
  59. metadata +141 -0
@@ -0,0 +1,151 @@
1
+ module RedmineCrm
2
+ class Currency
3
+ module Heuristics
4
+
5
+ # An robust and efficient algorithm for finding currencies in
6
+ # text. Using several algorithms it can find symbols, iso codes and
7
+ # even names of currencies.
8
+ # Although not recommendable, it can also attempt to find the given
9
+ # currency in an entire sentence
10
+ #
11
+ # Returns: Array (matched results)
12
+ def analyze(str)
13
+ return Analyzer.new(str, search_tree).process
14
+ end
15
+
16
+ private
17
+
18
+ # Build a search tree from the currency database
19
+ def search_tree
20
+ @_search_tree ||= {
21
+ :by_symbol => currencies_by_symbol,
22
+ :by_iso_code => currencies_by_iso_code,
23
+ :by_name => currencies_by_name
24
+ }
25
+ end
26
+
27
+ def currencies_by_symbol
28
+ {}.tap do |r|
29
+ table.each do |dummy, c|
30
+ symbol = (c[:symbol]||"").downcase
31
+ symbol.chomp!('.')
32
+ (r[symbol] ||= []) << c
33
+
34
+ (c[:alternate_symbols]||[]).each do |ac|
35
+ ac = ac.downcase
36
+ ac.chomp!('.')
37
+ (r[ac] ||= []) << c
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ def currencies_by_iso_code
44
+ {}.tap do |r|
45
+ table.each do |dummy,c|
46
+ (r[c[:iso_code].downcase] ||= []) << c
47
+ end
48
+ end
49
+ end
50
+
51
+ def currencies_by_name
52
+ {}.tap do |r|
53
+ table.each do |dummy,c|
54
+ name_parts = c[:name].downcase.split
55
+ name_parts.each {|part| part.chomp!('.')}
56
+
57
+ # construct one branch per word
58
+ root = r
59
+ while name_part = name_parts.shift
60
+ root = (root[name_part] ||= {})
61
+ end
62
+
63
+ # the leaf is a currency
64
+ (root[:value] ||= []) << c
65
+ end
66
+ end
67
+ end
68
+
69
+ class Analyzer
70
+ attr_reader :search_tree, :words
71
+ attr_accessor :str, :currencies
72
+
73
+ def initialize str, search_tree
74
+ @str = (str||'').dup
75
+ @search_tree = search_tree
76
+ @currencies = []
77
+ end
78
+
79
+ def process
80
+ format
81
+ return [] if str.empty?
82
+
83
+ search_by_symbol
84
+ search_by_iso_code
85
+ search_by_name
86
+
87
+ prepare_reply
88
+ end
89
+
90
+ def format
91
+ str.gsub!(/[\r\n\t]/,'')
92
+ str.gsub!(/[0-9][\.,:0-9]*[0-9]/,'')
93
+ str.gsub!(/[0-9]/, '')
94
+ str.downcase!
95
+ @words = str.split
96
+ @words.each {|word| word.chomp!('.'); word.chomp!(',') }
97
+ end
98
+
99
+ def search_by_symbol
100
+ words.each do |word|
101
+ if found = search_tree[:by_symbol][word]
102
+ currencies.concat(found)
103
+ end
104
+ end
105
+ end
106
+
107
+ def search_by_iso_code
108
+ words.each do |word|
109
+ if found = search_tree[:by_iso_code][word]
110
+ currencies.concat(found)
111
+ end
112
+ end
113
+ end
114
+
115
+ def search_by_name
116
+ # remember, the search tree by name is a construct of branches and leaf!
117
+ # We need to try every combination of words within the sentence, so we
118
+ # end up with a x^2 equation, which should be fine as most names are either
119
+ # one or two words, and this is multiplied with the words of given sentence
120
+
121
+ search_words = words.dup
122
+
123
+ while search_words.length > 0
124
+ root = search_tree[:by_name]
125
+
126
+ search_words.each do |word|
127
+ if root = root[word]
128
+ if root[:value]
129
+ currencies.concat(root[:value])
130
+ end
131
+ else
132
+ break
133
+ end
134
+ end
135
+
136
+ search_words.delete_at(0)
137
+ end
138
+ end
139
+
140
+ def prepare_reply
141
+ codes = currencies.map do |currency|
142
+ currency[:iso_code]
143
+ end
144
+ codes.uniq!
145
+ codes.sort!
146
+ codes
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,24 @@
1
+ module RedmineCrm
2
+ class Currency
3
+ module Loader
4
+ DATA_PATH = File.expand_path("../../../../config", __FILE__)
5
+
6
+ # Loads and returns the currencies stored in JSON files in the config directory.
7
+ #
8
+ # @return [Hash]
9
+ def load_currencies
10
+ currencies = parse_currency_file("currency_iso.json")
11
+ # currencies.merge! parse_currency_file("currency_non_iso.json")
12
+ # currencies.merge! parse_currency_file("currency_backwards_compatible.json")
13
+ end
14
+
15
+ private
16
+
17
+ def parse_currency_file(filename)
18
+ json = File.read("#{DATA_PATH}/#{filename}")
19
+ json.force_encoding(::Encoding::UTF_8) if defined?(::Encoding)
20
+ JSON.parse(json, :symbolize_names => true)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ module RedmineCrm
2
+ module TagsHelper
3
+ # See the README for an example using tag_cloud.
4
+ def tag_cloud(tags, classes)
5
+ return if tags.empty?
6
+
7
+ max_count = tags.sort_by(&:count).last.count.to_f
8
+
9
+ tags.each do |tag|
10
+ index = ((tag.count / max_count) * (classes.size - 1)).round
11
+ yield tag, classes[index]
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,38 @@
1
+ module RedmineCrm
2
+ module ActsAsVotable::Helpers
3
+
4
+ # this helper provides methods that help find what words are
5
+ # up votes and what words are down votes
6
+ #
7
+ # It can be called
8
+ #
9
+ # votable_object.votable_words.that_mean_true
10
+ #
11
+ module Words
12
+
13
+ def votable_words
14
+ VotableWords
15
+ end
16
+
17
+ end
18
+
19
+ class VotableWords
20
+
21
+ def self.that_mean_true
22
+ ['up', 'upvote', 'like', 'liked', 'positive', 'yes', 'good', 'true', 1, true]
23
+ end
24
+
25
+ def self.that_mean_false
26
+ ['down', 'downvote', 'dislike', 'disliked', 'negative', 'no', 'bad', 'false', 0, false]
27
+ end
28
+
29
+ # check is word is a true or bad vote
30
+ # if the word is unknown, then it counts it as a true/good
31
+ # vote. this exists to allow all voting to be good by default
32
+ def self.meaning_of word
33
+ !that_mean_false.include?(word)
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,61 @@
1
+ module RedmineCrm
2
+ module Liquid
3
+ class IssuesDrop < ::Liquid::Drop
4
+ def initialize(issues)
5
+ @issues = issues
6
+ end
7
+
8
+ def before_method(id)
9
+ issue = @issues.where(:id => id).first || Issue.new
10
+ IssueDrop.new issue
11
+ end
12
+
13
+ def all
14
+ @all ||= @issues.map do |issue|
15
+ IssueDrop.new issue
16
+ end
17
+ end
18
+
19
+ def each(&block)
20
+ all.each(&block)
21
+ end
22
+
23
+ def size
24
+ @issues.size
25
+ end
26
+ end
27
+
28
+ class IssueDrop < ::Liquid::Drop
29
+ include ActionView::Helpers::UrlHelper
30
+
31
+ delegate :id,
32
+ :subject,
33
+ :description,
34
+ :visible?,
35
+ :open?,
36
+ :start_date,
37
+ :due_date,
38
+ :overdue?,
39
+ :completed_percent,
40
+ :updated_on,
41
+ :created_on,
42
+ :to => :@issue
43
+
44
+ def initialize(issue)
45
+ @issue = issue
46
+ end
47
+
48
+ def link
49
+ link_to @issue.name, self.url
50
+ end
51
+
52
+ def url
53
+ Rails.application.routes.url_helpers.issue_path(@issue)
54
+ end
55
+
56
+ def author
57
+ @users ||= UsersDrop.new @issue.author
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,45 @@
1
+ module RedmineCrm
2
+ module Liquid
3
+ class NewssDrop < ::Liquid::Drop
4
+ def initialize(newss)
5
+ @newss = newss
6
+ end
7
+
8
+ def before_method(id)
9
+ news = @newss.where(:id => id).first || News.new
10
+ NewsDrop.new news
11
+ end
12
+
13
+ def last
14
+ NewsDrop.new News.last
15
+ end
16
+
17
+ def all
18
+ @all ||= @newss.map do |news|
19
+ NewsDrop.new news
20
+ end
21
+ end
22
+
23
+ def each(&block)
24
+ all.each(&block)
25
+ end
26
+
27
+ def size
28
+ @newss.size
29
+ end
30
+ end
31
+
32
+ class NewsDrop < ::Liquid::Drop
33
+
34
+ delegate :id, :title, :summary, :description, :visible?, :commentable?, :to => :@news
35
+
36
+ def initialize(news)
37
+ @news = news
38
+ end
39
+
40
+ def author
41
+ UserDrop.new @news.author
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,78 @@
1
+ module RedmineCrm
2
+ module Liquid
3
+ class ProjectsDrop < ::Liquid::Drop
4
+
5
+ def initialize(projects)
6
+ @projects = projects
7
+ end
8
+
9
+ def before_method(identifier)
10
+ project = @projects.where(:identifier => identifier).first || Project.new
11
+ ProjectDrop.new project
12
+ end
13
+
14
+ def all
15
+ @all ||= @projects.map do |project|
16
+ ProjectDrop.new project
17
+ end
18
+ end
19
+
20
+ def active
21
+ @active ||= @projects.select(&:active?).map do |project|
22
+ ProjectDrop.new project
23
+ end
24
+ end
25
+
26
+ def each(&block)
27
+ all.each(&block)
28
+ end
29
+
30
+ def size
31
+ @projects.size
32
+ end
33
+ end
34
+
35
+ class ProjectDrop < ::Liquid::Drop
36
+ include ActionView::Helpers::UrlHelper
37
+
38
+ delegate :id,
39
+ :identifier,
40
+ :name,
41
+ :is_public,
42
+ :description,
43
+ :visible?,
44
+ :active?,
45
+ :archived?,
46
+ :short_description,
47
+ :start_date,
48
+ :due_date,
49
+ :overdue?,
50
+ :completed_percent,
51
+ :to => :@project
52
+
53
+ def initialize(project)
54
+ @project = project
55
+ end
56
+
57
+ def link
58
+ link_to @project.name, self.url
59
+ end
60
+
61
+ def url
62
+ Rails.application.routes.url_helpers.project_path(@project)
63
+ end
64
+
65
+ def issues
66
+ @issues ||= IssuesDrop.new @project.issues.visible
67
+ end
68
+
69
+ def users
70
+ @users ||= UsersDrop.new @project.users
71
+ end
72
+
73
+ def subprojects
74
+ @subprojects ||= ProjectsDrop.new @project.children
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,59 @@
1
+ module RedmineCrm
2
+ module Liquid
3
+ class UsersDrop < ::Liquid::Drop
4
+ def initialize(users)
5
+ @users = users
6
+ end
7
+
8
+ def before_method(login)
9
+ user = @users.where(:login => login).first || User.new
10
+ UserDrop.new user
11
+ end
12
+
13
+ def current
14
+ UserDrop.new User.current
15
+ end
16
+
17
+ def all
18
+ @all ||= @users.map do |user|
19
+ UserDrop.new user
20
+ end
21
+ end
22
+
23
+ def each(&block)
24
+ all.each(&block)
25
+ end
26
+
27
+ def size
28
+ @users.size
29
+ end
30
+ end
31
+
32
+ class UserDrop < ::Liquid::Drop
33
+
34
+ delegate :id, :name, :firstname, :lastname, :mail, :active?, :admin?, :logged?, :language, :to => :@user
35
+
36
+ def initialize(user)
37
+ @user = user
38
+ end
39
+
40
+ def avatar
41
+ ApplicationController.helpers.avatar(@user)
42
+ end
43
+
44
+ def permissions
45
+ roles = @user.memberships.collect { |m| m.roles }.flatten.uniq
46
+ roles << (@user.logged? ? Role.non_member : Role.anonymous)
47
+ roles.map(&:permissions).flatten.uniq.map(&:to_s)
48
+ end
49
+
50
+ def groups
51
+ @user.groups.map(&:name)
52
+ end
53
+
54
+ def projects
55
+ ProjectsDrop.new @user.memberships.map(&:project).flatten.select(&:visible?).uniq
56
+ end
57
+ end
58
+ end
59
+ end