society 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: society
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Coraline Ada Ehmke
8
- - Kerri Miller
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2015-01-08 00:00:00.000000000 Z
11
+ date: 2015-03-11 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: activesupport
@@ -109,20 +108,6 @@ dependencies:
109
108
  - - "~>"
110
109
  - !ruby/object:Gem::Version
111
110
  version: '1.6'
112
- - !ruby/object:Gem::Dependency
113
- name: pry
114
- requirement: !ruby/object:Gem::Requirement
115
- requirements:
116
- - - ">="
117
- - !ruby/object:Gem::Version
118
- version: '0'
119
- type: :development
120
- prerelease: false
121
- version_requirements: !ruby/object:Gem::Requirement
122
- requirements:
123
- - - ">="
124
- - !ruby/object:Gem::Version
125
- version: '0'
126
111
  - !ruby/object:Gem::Dependency
127
112
  name: rake
128
113
  requirement: !ruby/object:Gem::Requirement
@@ -193,10 +178,9 @@ dependencies:
193
178
  - - ">="
194
179
  - !ruby/object:Gem::Version
195
180
  version: '0'
196
- description: Social graph for Ruby objects
181
+ description: Social graph for Ruby objects. Based on an original idea by Kerri Miller.
197
182
  email:
198
183
  - coraline@instructure.com
199
- - kerrizor@gmail.com
200
184
  executables:
201
185
  - society
202
186
  extensions: []
@@ -214,11 +198,8 @@ files:
214
198
  - bin/society
215
199
  - bower.json
216
200
  - lib/society.rb
217
- - lib/society/association_processor.rb
218
201
  - lib/society/cli.rb
219
- - lib/society/clusterer.rb
220
202
  - lib/society/edge.rb
221
- - lib/society/formatter/graph/json.rb
222
203
  - lib/society/formatter/report/html.rb
223
204
  - lib/society/formatter/report/json.rb
224
205
  - lib/society/formatter/report/templates/components/.gitignore
@@ -226,26 +207,19 @@ files:
226
207
  - lib/society/formatter/report/templates/components/society-assets/society.css
227
208
  - lib/society/formatter/report/templates/components/society-assets/society.js
228
209
  - lib/society/formatter/report/templates/index.htm.haml
210
+ - lib/society/node.rb
229
211
  - lib/society/object_graph.rb
230
212
  - lib/society/parser.rb
231
- - lib/society/reference_processor.rb
232
213
  - lib/society/version.rb
233
214
  - society.gemspec
234
- - society_graph.json
235
- - spec/association_processor_spec.rb
236
215
  - spec/cli_spec.rb
237
- - spec/clusterer_spec.rb
238
- - spec/fixtures/clustering/clusterer_fixtures.rb
239
- - spec/fixtures/clustering/edges_1.txt
240
216
  - spec/fixtures/for_parser_spec/whaler.rb
241
- - spec/formatter/graph/json_spec.rb
242
217
  - spec/formatter/report/html_spec.rb
243
218
  - spec/formatter/report/json_spec.rb
244
219
  - spec/object_graph_spec.rb
245
220
  - spec/parser_spec.rb
246
- - spec/reference_processor_spec.rb
247
221
  - spec/spec_helper.rb
248
- homepage: https://github.com/Bantik/society
222
+ homepage: https://github.com/CoralineAda/society
249
223
  licenses:
250
224
  - MIT
251
225
  metadata: {}
@@ -270,16 +244,10 @@ signing_key:
270
244
  specification_version: 4
271
245
  summary: Social graph for Ruby objects
272
246
  test_files:
273
- - spec/association_processor_spec.rb
274
247
  - spec/cli_spec.rb
275
- - spec/clusterer_spec.rb
276
- - spec/fixtures/clustering/clusterer_fixtures.rb
277
- - spec/fixtures/clustering/edges_1.txt
278
248
  - spec/fixtures/for_parser_spec/whaler.rb
279
- - spec/formatter/graph/json_spec.rb
280
249
  - spec/formatter/report/html_spec.rb
281
250
  - spec/formatter/report/json_spec.rb
282
251
  - spec/object_graph_spec.rb
283
252
  - spec/parser_spec.rb
284
- - spec/reference_processor_spec.rb
285
253
  - spec/spec_helper.rb
@@ -1,206 +0,0 @@
1
- module Society
2
-
3
- class AssociationProcessor
4
-
5
- ACTIVE_MODEL_ASSOCIATIONS = %w[belongs_to has_one has_many has_and_belongs_to_many]
6
-
7
- attr_reader :classes, :associations, :unresolved_associations
8
-
9
- def initialize(classes)
10
- @classes = classes
11
- process
12
- end
13
-
14
- private
15
-
16
- def process
17
- default_resolver = DefaultResolver.new(classes)
18
- through_resolver = ThroughResolver.new(classes)
19
- poly_resolver = PolymorphicResolver.new(default_resolver)
20
-
21
- classes.each do |klass|
22
- klass.macros.select do |macro|
23
- ACTIVE_MODEL_ASSOCIATIONS.include?(macro.name)
24
- # TODO: make sure macro.target is 'self' (it pretty much always will be)
25
- end.each do |association|
26
- through_resolver.process(association, klass) or
27
- poly_resolver.process(association, klass) or
28
- default_resolver.process(association, klass)
29
- end
30
- end
31
-
32
- @associations = default_resolver.associations
33
- @unresolved_associations = default_resolver.unresolved_associations
34
-
35
- @associations.concat(poly_resolver.associations).concat(through_resolver.associations)
36
- @unresolved_associations.concat(through_resolver.unresolved_associations)
37
- end
38
-
39
-
40
- class ThroughResolver
41
-
42
- attr_reader :associations, :unresolved_associations
43
-
44
- def initialize(classes)
45
- @classes = classes
46
- @my_own_default_resolver = DefaultResolver.new(classes)
47
- @associations = []
48
- @unresolved_associations = []
49
- end
50
-
51
- def process(association, klass)
52
- return false unless thru = through_of(association)
53
-
54
- if source_type = association.arguments.last.to_hash[:source_type]
55
- target = @classes.detect { |cls| cls.full_name == source_type }
56
- else
57
- joiner = klass.macros.detect do |macro|
58
- ACTIVE_MODEL_ASSOCIATIONS.include?(macro.name) && macro.arguments.first.value == thru
59
- end
60
- joining_class_entities = @my_own_default_resolver.all_classes_for(joiner)
61
-
62
- source_str = source_of(association).to_s
63
-
64
- target = joining_class_entities.reduce(nil) do |_,cls|
65
- assoc = find_association_in(cls, source_str)
66
- break @my_own_default_resolver.process(assoc, cls) if assoc
67
- end
68
- end
69
-
70
- if target
71
- @associations << Edge.new(from: klass,
72
- to: target,
73
- meta: {
74
- type: :through_association,
75
- macro: association })
76
- else
77
- @unresolved_associations << { class: klass,
78
- macro: association,
79
- thru_macro: joiner,
80
- joining_classes: joining_class_entities }
81
- end
82
- true
83
- end
84
-
85
- private
86
-
87
- def find_association_in(klass, name)
88
- klass.macros.detect do |macro|
89
- ACTIVE_MODEL_ASSOCIATIONS.include?(macro.name) &&
90
- macro.arguments.first.value.to_s.singularize == name.singularize
91
- end
92
- end
93
-
94
- def through_of(association)
95
- last_arg = association.arguments.last
96
- last_arg.is_a?(Analyst::Entities::Hash) && last_arg.to_hash[:through]
97
- end
98
-
99
- def source_of(association)
100
- association.arguments.last.to_hash[:source] || association.arguments.first.value
101
- end
102
-
103
- end
104
-
105
-
106
- class DefaultResolver
107
-
108
- attr_reader :associations, :unresolved_associations
109
-
110
- def initialize(classes)
111
- @classes = classes
112
- @associations = []
113
- @unresolved_associations = []
114
- end
115
-
116
- def process(association, klass)
117
- if target = all_classes_for(association).first
118
- @associations << Edge.new(from: klass,
119
- to: target,
120
- meta: {
121
- type: :association,
122
- macro: association })
123
- else
124
- @unresolved_associations << { class: klass,
125
- target_name: target_class_name_for(association),
126
- macro: association }
127
- end
128
- target
129
- end
130
-
131
- def all_classes_for(association)
132
- target_name = target_class_name_for(association)
133
- classes.select { |klass| klass.full_name == target_name }
134
- end
135
-
136
- private
137
-
138
- attr_reader :classes
139
-
140
- def target_class_name_for(association)
141
- last_arg = association.arguments.last
142
- if last_arg.is_a? Analyst::Entities::Hash
143
- target_name = last_arg.to_hash[:class_name]
144
- end
145
- target_name ||= association.arguments.first.value.to_s.pluralize.classify
146
- end
147
-
148
- end
149
-
150
-
151
- class PolymorphicResolver
152
-
153
- def initialize(default_resolver)
154
- @default_resolver = default_resolver
155
- @polymorphics = []
156
- @ases = []
157
- end
158
-
159
- # stores off any `polymorphic: true` or `as: :something` associations for
160
- # later processing. also does default processing on `as: :something`
161
- # associations. returns true iff association requires no further processing.
162
- def process(association, klass)
163
- last_arg = association.arguments.last
164
- return false unless last_arg.is_a?(Analyst::Entities::Hash)
165
-
166
- opts = last_arg.to_hash
167
- if opts.key? :polymorphic
168
- @polymorphics << { class: klass,
169
- key: association.arguments.first.value,
170
- macro: association }
171
- return true
172
-
173
- elsif opts.key? :as
174
- if target = @default_resolver.process(association, klass)
175
- @ases << { class: klass, target: target,
176
- macro: association, key: opts[:as] }
177
- end
178
- return true
179
- end
180
-
181
- false
182
- end
183
-
184
- def associations
185
- associations = []
186
- @polymorphics.each do |poly|
187
- matching = @ases.select do |as|
188
- as[:key] == poly[:key] && as[:target] == poly[:class]
189
- end
190
- matching.each do |as|
191
- associations << Edge.new(from: poly[:class],
192
- to: as[:class],
193
- meta: {
194
- type: :polymorphic_association,
195
- macro: poly[:macro],
196
- complement: as[:macro] })
197
- end
198
- end
199
- associations
200
- end
201
- end
202
-
203
- end
204
-
205
- end
206
-
@@ -1,188 +0,0 @@
1
- # This file has been translated from the `minimcl` perl script, which was
2
- # sourced from the MCL-edge library, release 14-137. The homepage for MCL-edge
3
- # is http://micans.org/mcl
4
- #
5
- # The original copyright for `minimcl` is as follows:
6
- #
7
- # (C) Copyright 2006, 2007, 2008, 2009 Stijn van Dongen
8
- #
9
- # This file is part of MCL. You can redistribute and/or modify MCL under the
10
- # terms of the GNU General Public License; either version 3 of the License or
11
- # (at your option) any later version. You should have received a copy of the
12
- # GPL along with MCL, in the file COPYING.
13
-
14
- module Society
15
- class Clusterer
16
-
17
- def initialize(params={})
18
- @params = DEFAULT_PARAMS.merge(params)
19
- end
20
-
21
- # returns an array of arrays of nodes
22
- def cluster(graph)
23
- m = matrix_from(graph)
24
- clusters = mcl(m)
25
- clusters.map { |index, members| members.keys }
26
- .sort_by(&:size).reverse
27
- end
28
-
29
- private
30
-
31
- attr_reader :params
32
-
33
- DEFAULT_PARAMS = {
34
- inflation: 2.0
35
- }
36
-
37
- # TODO: "weights" are ignored right now, but soon will be an attribute of
38
- # the edge
39
- def matrix_from(graph)
40
- matrix = SparseMatrix.new
41
- graph.edges.each do |edge|
42
- a = edge.from
43
- b = edge.to
44
- matrix[a][b] = 1
45
- matrix[b][a] = 1
46
- end
47
- matrix
48
- end
49
-
50
- def mcl(matrix)
51
- matrix_add_loops(matrix)
52
- matrix_make_stochastic(matrix)
53
- chaos = 1.0
54
- while (chaos > 0.001) do
55
- sq = matrix_square(matrix)
56
- chaos = matrix_inflate(sq)
57
- matrix = sq
58
- end
59
- matrix_interpret(matrix)
60
- end
61
-
62
- def matrix_square(matrix)
63
- squared = SparseMatrix.new
64
- matrix.each do |node, vector|
65
- squared[node] = matrix_multiply_vector(matrix, vector)
66
- end
67
- squared
68
- end
69
-
70
- def matrix_multiply_vector(matrix, vector)
71
- result_vec = SparseVector.new
72
- vector.each do |entry, val|
73
- matrix[entry].each do |f, matrix_val|
74
- result_vec[f] += val * matrix_val
75
- end
76
- end
77
- result_vec
78
- end
79
-
80
- def matrix_make_stochastic(matrix)
81
- matrix_inflate(matrix, 1)
82
- end
83
-
84
- def matrix_add_loops(matrix)
85
- matrix.each do |key,_|
86
- matrix[key][key] = 1.0
87
- matrix[key][key] = vector_max(matrix[key])
88
- end
89
- end
90
-
91
- def vector_max(vector)
92
- vector.values.max || 0.0
93
- end
94
-
95
- def vector_sum(vector)
96
- vector.values.reduce(&:+) || 0.0
97
- end
98
-
99
- # prunes small elements as well
100
- def matrix_inflate(matrix, inflation = params[:inflation])
101
- chaos = 0.0
102
- matrix.each do |node, vector|
103
- sum = 0.0
104
- sumsq = 0.0
105
- max = 0.0
106
- vector.each do |node2, value|
107
- vector.delete node2 and next if value < 0.00001
108
-
109
- inflated = value ** inflation
110
- vector[node2] = inflated
111
- sum += inflated
112
- end
113
- if sum > 0.0
114
- vector.each do |node2, value|
115
- vector[node2] /= sum
116
- sumsq += vector[node2] ** 2
117
- max = [vector[node2], max].max
118
- end
119
- end
120
- chaos = [max - sumsq, chaos].max
121
- end
122
- chaos # only meaningful if input is stochastic
123
- end
124
-
125
- # assumes but does not check doubly idempotent matrix.
126
- # can handle attractor systems of size < 10.
127
- # recognizes/preserves overlap.
128
- def matrix_interpret(matrix)
129
- clusters = SparseMatrix.new
130
- attrid = {}
131
- clid = 0
132
-
133
- # crude removal of small elements
134
- matrix.each do |n, vec|
135
- vec.each do |nb, val|
136
- matrix[n].delete nb if val < 0.1
137
- end
138
- end
139
-
140
- attr = {}
141
- matrix.each_key do |key|
142
- attr[key] = 1 if matrix[key].key? key
143
- end
144
-
145
- attr.each_key do |a|
146
- next if attrid.key?(a)
147
- aa = [a]
148
- while aa.size > 0 do
149
- bb = []
150
- aa.each do |aaa|
151
- attrid[aaa] = clid
152
- matrix[aaa].each_key { |akey| bb.push(akey) if attr.key? akey }
153
- end
154
- aa = bb.select { |b| !attrid.key?(b) }
155
- end
156
- clid += 1
157
- end
158
-
159
- matrix.each do |n, val|
160
- if !attr.key?(n)
161
- val.keys.select { |x| attr.key? x }.each do |a|
162
- clusters[attrid[a]][n] += 1
163
- end
164
- else
165
- clusters[attrid[n]][n] += 1
166
- end
167
- end
168
-
169
- clusters
170
- end
171
-
172
-
173
- module SparseMatrix
174
- def self.new
175
- Hash.new do |hash, key|
176
- hash[key] = SparseVector.new
177
- end
178
- end
179
- end
180
-
181
- module SparseVector
182
- def self.new
183
- Hash.new(0.0)
184
- end
185
- end
186
- end
187
- end
188
-