motion-set 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []