motion-set 0.1.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,90 @@
1
+ # Implementation of Ruby `set` module
2
+
3
+ This gems implements `Set` class from `set` standard library
4
+ of Ruby 1.9.3. See [Ruby 1.9.3 `Set` API documentation](
5
+ http://ruby-doc.org/stdlib-1.9.3/libdoc/set/rdoc/Set.html#method-i-flatten-21)
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'motion-set'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install motion-set
20
+
21
+ ## Implementation details
22
+
23
+ ### No `require`
24
+
25
+ RubyMotion does not support `require`. Instead, when you
26
+ install this gem, `Set` class will be globally available.
27
+
28
+ ### `Set` is `NSMutableSet`
29
+
30
+ `Set` is implemented as an alias to `NSMutableSet`, which
31
+ it turn is extended to accomodate all Ruby set methods.
32
+ This is similar to how other RubyMotion data types
33
+ (like `Array`) are implemented.
34
+
35
+ Advantages of this approach are:
36
+
37
+ 1. Interoperability with native APIs:
38
+ * You can pass `Set` objects to APIs expecting `NSSet`
39
+ or `NSMutableSet`.
40
+ * Whenever a native API returns an `NSMutableSet` you
41
+ can treat it as Ruby set.
42
+ 2. There's no performance penalty, because there is no
43
+ unnecessary indirection.
44
+
45
+ However, there are some things you need to note:
46
+
47
+ ### No `nil` in sets
48
+
49
+ `NSMutableSet` does not support adding `nil` object,
50
+ which applies to your Ruby sets.
51
+
52
+ This could fail in subtle ways, for example if you try
53
+ to call `#map!` with a block which returns `nil`.
54
+
55
+ > This could have been avoided if the implementation
56
+ > checked when `nil` is added, and instead stored a
57
+ > private singelton sentinel fake nil object, which would
58
+ > be converted back to `nil` when necessary. However,
59
+ > this would create a challenge for interoperability
60
+ > with native APIs: what should this object represent
61
+ > in Objective-C world?
62
+ >
63
+ > If you have opinion on this, you are welcom to
64
+ > [comment on this issue](
65
+ > https://github.com/robocat/motion-set/issues/1).
66
+
67
+ ### No `#divide` method
68
+
69
+ [`#divide`](
70
+ http://ruby-doc.org/stdlib-1.9.3/libdoc/set/rdoc/Set.html#method-i-divide)
71
+ method is not implemented. You are welcome to contribute.
72
+
73
+ ### No `SortedSet`
74
+
75
+ [`SortedSet`](
76
+ http://ruby-doc.org/stdlib-1.9.3/libdoc/set/rdoc/SortedSet.html)
77
+ is not implemented. You are welcome to contribute.
78
+
79
+ ### No Android support
80
+
81
+ There is no Android support, but you are welcome to
82
+ contribute.
83
+
84
+ ## Contributing
85
+
86
+ 1. Fork it
87
+ 2. Create your feature branch: `git checkout -b my-new-feature`
88
+ 3. Commit your changes: `git commit -am 'Add some feature'`
89
+ 4. Push to the branch: `git push origin my-new-feature`
90
+ 5. Create new Pull Request
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+
3
+ unless defined?(Motion::Project::Config)
4
+ raise "This file must be required within a RubyMotion project Rakefile."
5
+ end
6
+
7
+ lib_dir_path = File.dirname(File.expand_path(__FILE__))
8
+ Motion::Project::App.setup do |app|
9
+ app.files.unshift(Dir.glob(File.join(lib_dir_path, "project/**/*.rb")))
10
+ end
@@ -0,0 +1,173 @@
1
+ Set = NSMutableSet
2
+
3
+ class NSMutableSet
4
+ include Enumerable
5
+
6
+ def self.new(enum=nil)
7
+ if enum
8
+ enum.to_set
9
+ else
10
+ alloc.init
11
+ end
12
+ end
13
+
14
+ def self.[](*ary)
15
+ new.tap { |set| ary.each { |item| set.add item } }
16
+ end
17
+
18
+ def inspect
19
+ "#<Set: {#{self.to_a.join ', '}}>"
20
+ end
21
+
22
+ def intersection(enum); send_to_copy(:'intersectSet', enum) end
23
+ alias_method :&, :intersection
24
+
25
+ def union(enum); send_to_copy(:'unionSet:', enum) end
26
+ alias_method :|, :union
27
+ alias_method :+, :union
28
+
29
+ def difference(enum); send_to_copy(:'minusSet:', enum) end
30
+ alias_method :-, :difference
31
+
32
+ # Why can't you just: alias_method :add, :'addObject:'
33
+ def add(o); addObject o end
34
+ alias_method :<<, :add
35
+
36
+ def ^(enum)
37
+ ((self | enum) - (self & enum))
38
+ end
39
+
40
+ def add?(o)
41
+ (include? o) ? nil : (add o)
42
+ end
43
+
44
+ def classify(&block)
45
+ return to_enum(__method__) unless block_given?
46
+ reduce({}) do |hash, item|
47
+ classifier = block.call item
48
+ hash[classifier] ||= Set[]
49
+ hash[classifier].add item
50
+ hash
51
+ end
52
+ end
53
+
54
+ alias_method :clear, :removeAllObjects
55
+
56
+ def collect!(&block)
57
+ return to_enum(__method__) unless block_given?
58
+ replace collect(&block)
59
+ end
60
+ alias_method :map!, :collect!
61
+
62
+ # Why can't you just: alias_method :delete, :'removeObject:'
63
+ def delete(o); removeObject o end
64
+
65
+ def delete?(o)
66
+ (include? o) ? (delete o) : nil
67
+ end
68
+
69
+ def keep_if(&block)
70
+ return to_enum(__method__) unless block_given?
71
+ each { |item| delete item unless block.call item }
72
+ self
73
+ end
74
+
75
+ def delete_if(&block)
76
+ return to_enum(__method__) unless block_given?
77
+ each { |item| delete item if block.call item }
78
+ self
79
+ end
80
+
81
+ # Why can't you just: alias_method :length, :count
82
+ def length; count end
83
+ alias_method :size, :length
84
+
85
+ def empty?; count == 0 end
86
+
87
+ def flatten
88
+ self.to_enum(:flat_each).to_set
89
+ end
90
+
91
+ def flatten!
92
+ copy = self.to_set
93
+ # Not sure why self.to_enum does not work in this case:
94
+ replace copy.to_enum :flat_each
95
+ (copy == self) ? nil : self
96
+ end
97
+
98
+ alias_method :include?, :containsObject
99
+ alias_method :member?, :containsObject
100
+
101
+ def merge(enum)
102
+ enum.each { |item| add item }
103
+ self
104
+ end
105
+
106
+ def replace(enum)
107
+ clear
108
+ merge(enum)
109
+ end
110
+
111
+ def subtract(enum)
112
+ enum.each { |item| delete item }
113
+ self
114
+ end
115
+
116
+ def subset?(set)
117
+ enforce_set(set) && isSubsetOfSet(set)
118
+ end
119
+
120
+ def superset?(set)
121
+ enforce_set(set) && set.isSubsetOfSet(self)
122
+ end
123
+
124
+ def proper_subset?(set)
125
+ (subset? set) && (self != set)
126
+ end
127
+
128
+ def proper_superset?(set)
129
+ (superset? set) && (self != set)
130
+ end
131
+
132
+ def reject!(&block)
133
+ return to_enum(__method__) unless block_given?
134
+ each_returning_self_or_nil { |item| delete item if block.call item }
135
+ end
136
+
137
+ def select!(&block)
138
+ return to_enum(__method__) unless block_given?
139
+ each_returning_self_or_nil { |item| delete item unless block.call item }
140
+ end
141
+
142
+ protected
143
+
144
+ def flat_each(&block)
145
+ each do |item|
146
+ (item.instance_of? self.class) ? item.flat_each(&block) : block.(item)
147
+ end
148
+ end
149
+
150
+ private
151
+
152
+ def each_returning_self_or_nil(&block)
153
+ old_size = self.size
154
+ each(&block)
155
+ (old_size != size) ? self : nil
156
+ end
157
+
158
+ def enforce_set(set)
159
+ raise ArgumentError, 'value must be a set' unless set.is_a? self.class
160
+ true
161
+ end
162
+
163
+ def send_to_copy(symbol, enum)
164
+ self.to_set.tap { |set| set.send(symbol, enum.to_set) }
165
+ end
166
+
167
+ end
168
+
169
+ class Enumerable
170
+ def to_set
171
+ Set[*self]
172
+ end
173
+ end
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: motion-set
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Vladimir Keleshev
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-10-16 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: Set implementation for RubyMotion
31
+ email:
32
+ - vladimir@keleshev.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - README.md
38
+ - lib/motion-set.rb
39
+ - lib/project/motion-set.rb
40
+ homepage: ''
41
+ licenses:
42
+ - ''
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ! '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubyforge_project:
61
+ rubygems_version: 1.8.23
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: Set implementation for RubyMotion
65
+ test_files: []