under-os-core 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,85 @@
1
+ #
2
+ # A little events handling concern
3
+ #
4
+ module UnderOs::Events
5
+
6
+ def on(event, *args, &block)
7
+ Listeners.add(self, event, *args, block)
8
+ end
9
+
10
+ def off(event)
11
+ Listeners.remove(self, event)
12
+ end
13
+
14
+ def emit(event, params={})
15
+ Listeners.kick(self, event, params)
16
+ end
17
+
18
+ module Listeners
19
+ extend self
20
+
21
+ def list(model, event=nil)
22
+ @listeners ||= Hash.new{|h,k| h[k] = Hash.new{|h,k| h[k] = []} }
23
+ event ? @listeners[model][event.to_sym] : @listeners[model]
24
+ end
25
+
26
+ def add(model, event, *args, block)
27
+ list(model, event) << [block, *args]
28
+ model
29
+ end
30
+
31
+ def all(model, event)
32
+ list(model, event)
33
+ end
34
+
35
+ def remove(model, event)
36
+ list(model).delete event.to_sym
37
+ model
38
+ end
39
+
40
+ def kick(model, event, params)
41
+ event = Event.new(event, params) unless event.is_a?(Event)
42
+
43
+ all(model, event.name).each do |block, method_name, *args|
44
+ if !block && method_name
45
+ block = Proc.new{ |e|
46
+ a = method(method_name).arity == 0 ? [] : [e];
47
+ __send__(method_name, *a) }
48
+ context = model
49
+ elsif block && method_name # <- considering it's a context reference
50
+ context = method_name
51
+ else
52
+ context = nil
53
+ end
54
+
55
+ args = block.arity == 0 ? [] : [event]
56
+
57
+ if context
58
+ context.instance_exec *args, &block
59
+ else
60
+ block.call *args
61
+ end
62
+ end
63
+
64
+ model
65
+ end
66
+ end
67
+
68
+ class Event
69
+ attr_reader :name, :params
70
+
71
+ def initialize(name, params)
72
+ @name = name.to_sym
73
+ @params = params
74
+ end
75
+
76
+ def method_missing(name, *args, &block)
77
+ if @params.has_key?(name.to_sym)
78
+ @params[name.to_sym]
79
+ else
80
+ super name, *args, &block
81
+ end
82
+ end
83
+ end
84
+
85
+ end
@@ -0,0 +1,110 @@
1
+ class UnderOs::File
2
+ attr_reader :path, :mode
3
+
4
+ def self.open(path, *args, &block)
5
+ new path, *args, &block
6
+ end
7
+
8
+ def self.read(path, *args)
9
+ new(path, *args).read
10
+ end
11
+
12
+ def self.write(path, content)
13
+ new(path, "w"){|f| f.write(content) }
14
+ end
15
+
16
+ def self.size(path)
17
+ new(path).size
18
+ end
19
+
20
+ def self.delete(path)
21
+ NSFileManager.defaultManager.removeItemAtPath(UnderOs::File.path(path), error:nil)
22
+ end
23
+
24
+ def self.path(path)
25
+ path.to_s[0] == '/' ? path : NSHomeDirectory().stringByAppendingPathComponent(path)
26
+ end
27
+
28
+ def self.tmp(filename, mode="w", &block)
29
+ new NSTemporaryDirectory().stringByAppendingPathComponent(filename), mode, &block
30
+ end
31
+
32
+ def self.exists?(path, is_dir=nil)
33
+ NSFileManager.defaultManager.fileExistsAtPath(UnderOs::File.path(path), isDirectory:is_dir)
34
+ end
35
+
36
+ def self.file?(path)
37
+ exists?(path, false)
38
+ end
39
+
40
+ def self.dir?(path)
41
+ exists?(path, true)
42
+ end
43
+
44
+ def initialize(path, mode="r", &block)
45
+ @path = UnderOs::File.path(path)
46
+ @mode = mode
47
+
48
+ yield(self) if block_given?
49
+ end
50
+
51
+ def url
52
+ @url ||= NSURL.fileURLWithPath(@path)
53
+ end
54
+
55
+ def read(size=nil)
56
+ open
57
+ data = if size == nil
58
+ @handle.readDataToEndOfFile
59
+ else
60
+ @handle.readDataOfLength(size)
61
+ end
62
+ close
63
+
64
+ @mode == "b" ? data : NSString.alloc.initWithData(data, encoding:NSUTF8StringEncoding)
65
+ end
66
+
67
+ def write(content)
68
+ if ! UnderOs::File.exists?(@path)
69
+ NSFileManager.defaultManager.createFileAtPath @path, contents:nil, attributes:nil
70
+ end
71
+
72
+ content = content.to_data('utf-8') if content.is_a?(String)
73
+
74
+ open
75
+ @handle.writeData content
76
+ close
77
+ end
78
+
79
+ def open
80
+ @handle = if @mode == "r"
81
+ NSFileHandle.fileHandleForReadingAtPath(@path)
82
+ else
83
+ NSFileHandle.fileHandleForWritingAtPath(@path)
84
+ end
85
+
86
+ @handle.seekToEndOfFile if ["w+", "a"].include?(@mode)
87
+ end
88
+
89
+ def close
90
+ @handle.closeFile
91
+ @handle = nil
92
+ end
93
+
94
+ def seek(offset)
95
+ @handle.seekToFileOffset(offset)
96
+ end
97
+
98
+ def rewind
99
+ seek 0
100
+ end
101
+
102
+ def size
103
+ NSFileManager.defaultManager.attributesOfItemAtPath(@path, error: nil).fileSize
104
+ end
105
+
106
+ def truncate(size)
107
+ @handle.truncateFileAtOffset(size)
108
+ end
109
+
110
+ end
@@ -0,0 +1,50 @@
1
+ #
2
+ # Generic Point/Size unit
3
+ #
4
+ class UnderOs::Point
5
+ attr_accessor :x, :y
6
+
7
+ def initialize(x, y=nil)
8
+ if x.is_a?(UnderOs::Point)
9
+ y = x.y if x.y
10
+ x = x.x
11
+ elsif x.is_a?(Hash)
12
+ y = x[:y] || x['y'] || nil
13
+ x = x[:x] || x['x'] || nil
14
+ end
15
+
16
+ @x = x
17
+ @y = y
18
+ end
19
+
20
+ def ==(*args)
21
+ point = UnderOs::Point.new(*args) # normalizing
22
+ x == point.x && y == point.y
23
+ end
24
+
25
+ def *(multiplier)
26
+ UnderOs::Point.new(x: x * multiplier, y: y * multiplier)
27
+ end
28
+
29
+ def /(divider)
30
+ UnderOs::Point.new(x: x / divider.to_f, y: y / divider.to_f)
31
+ end
32
+
33
+ def -(point)
34
+ point = point.is_a?(Numeric) ? UnderOs::Point.new(x: point, y: point) : UnderOs::Point.new(point)
35
+ UnderOs::Point.new(x: x - point.x, y: y - point.y)
36
+ end
37
+
38
+ def +(point)
39
+ point = point.is_a?(Numeric) ? UnderOs::Point.new(x: point, y: point) : UnderOs::Point.new(point)
40
+ UnderOs::Point.new(x: x + point.x, y: y + point.y)
41
+ end
42
+
43
+ def to_s
44
+ "x=#{x} y=#{y}"
45
+ end
46
+
47
+ def inspect
48
+ "#<#{self.class.name}:0x#{__id__.to_s(16)} #{to_s}>"
49
+ end
50
+ end
@@ -0,0 +1,9 @@
1
+ class UnderOs::Screen
2
+ def self.size
3
+ # TODO make it handle the screen orientation
4
+ UnderOs::Point.new({
5
+ x: UIScreen.mainScreen.bounds.size.width,
6
+ y: UIScreen.mainScreen.bounds.size.height
7
+ })
8
+ end
9
+ end
@@ -0,0 +1,65 @@
1
+ class UnderOs::Timer
2
+ def self.in(duration, options={}, &block)
3
+ duration = Duration.new(duration) if duration.is_a?(Numeric)
4
+ new duration.to_f, options.merge(repeat: false), &block
5
+ end
6
+
7
+ def self.every(duration, options={}, &block)
8
+ duration = Duration.new(duration) if duration.is_a?(Numeric)
9
+ new duration.to_f, options.merge(repeat: true), &block
10
+ end
11
+
12
+ attr_reader :block, :counter, :interval, :repeats, :_
13
+
14
+ def initialize(seconds, options={}, &block)
15
+ @block = block
16
+ @counter = options[:repeat].to_i if options[:repeat].is_a?(Numeric)
17
+ @interval = seconds
18
+ @repeats = options[:repeat] != false
19
+
20
+ @_ = NSTimer.scheduledTimerWithTimeInterval @interval,
21
+ target: self, selector: :kick, userInfo: nil, repeats: @repeats
22
+ end
23
+
24
+ def stop
25
+ @_.invalidate
26
+ self
27
+ end
28
+
29
+ def kick
30
+ @block.call
31
+ stop if @counter && (@counter -= 1) <= 0
32
+ end
33
+
34
+ class Duration
35
+ attr_reader :seconds
36
+
37
+ def initialize(seconds)
38
+ @seconds = seconds.to_f
39
+ end
40
+
41
+ def to_f
42
+ @seconds
43
+ end
44
+
45
+ def to_i
46
+ to_f.to_i
47
+ end
48
+
49
+ def to_s
50
+ "#{to_f} seconds"
51
+ end
52
+
53
+ def ==(duration)
54
+ duration.is_a?(UnderOs::Timer::Duration) && duration.seconds == @seconds
55
+ end
56
+
57
+ def later(options={}, &block)
58
+ UnderOs::Timer.in self, options={}, &block
59
+ end
60
+
61
+ def repeat(options={}, &block)
62
+ UnderOs::Timer.every self, options={}, &block
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,32 @@
1
+ describe JSON do
2
+ describe ".parse" do
3
+ it "parses correct json strings" do
4
+ JSON.parse('{"a":1,"b":true,"c":["data"]}').should == {
5
+ "a" => 1, "b" => true, "c" => ["data"]
6
+ }
7
+ end
8
+
9
+ it "raises an exception on malformed data" do
10
+ -> {
11
+ JSON.parse("malformed")
12
+ }.should.raise(JSON::Malformed)
13
+ end
14
+ end
15
+
16
+ describe ".generate" do
17
+ it "generates JSON string out of objects" do
18
+ JSON.generate({a:1, b:true, c:[:data]}).should ==
19
+ '{"a":1,"b":true,"c":["data"]}'
20
+ end
21
+
22
+ it "generates pretty print when asked" do
23
+ JSON.generate({a:1, b:true, c:[:data]}, :pretty).should ==
24
+ "{\n \"a\" : 1,\n \"b\" : true,\n \"c\" : [\n \"data\"\n ]\n}"
25
+ end
26
+
27
+ it "allows to export things directly of objects" do
28
+ {a:1, b:true, c:[:data]}.to_json.should ==
29
+ '{"a":1,"b":true,"c":["data"]}'
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,37 @@
1
+ describe Numeric do
2
+
3
+ describe '#milliseconds' do
4
+ it "returns timer duration in milliseconds" do
5
+ 10.milliseconds.should == UnderOs::Timer::Duration.new(0.01)
6
+ end
7
+
8
+ it "has the 'ms' alias" do
9
+ 10.milliseconds.should == 10.ms
10
+ end
11
+ end
12
+
13
+ describe '#seconds' do
14
+ it "returns the time duration in seconds" do
15
+ 10.seconds.should == UnderOs::Timer::Duration.new(10)
16
+ end
17
+ end
18
+
19
+ describe '#minutes' do
20
+ it "returns the time duration in minutes" do
21
+ 10.minutes.should == UnderOs::Timer::Duration.new(10 * 60)
22
+ end
23
+ end
24
+
25
+ describe '#hours' do
26
+ it "returns the time duration in hours" do
27
+ 10.hours.should == UnderOs::Timer::Duration.new(10 * 60 * 60)
28
+ end
29
+ end
30
+
31
+ describe '#days' do
32
+ it "returns the time duration in days" do
33
+ 10.days.should == UnderOs::Timer::Duration.new(10 * 60 * 60 * 24)
34
+ end
35
+ end
36
+
37
+ end
@@ -0,0 +1,101 @@
1
+ describe String do
2
+ describe '#underscore' do
3
+ it "converts camelized strings into underscored" do
4
+ "SomeStuff".underscore.should == 'some_stuff'
5
+ end
6
+
7
+ it "converts dashed strings into underscored as well" do
8
+ "some-stuff".underscore.should == "some_stuff"
9
+ end
10
+ end
11
+
12
+ describe "#camelize" do
13
+ it "converts underscored strings into camelized" do
14
+ "some_stuff".camelize.should == "someStuff"
15
+ end
16
+
17
+ it "converts dashed strings into camelized as well" do
18
+ "some-stuff".camelize.should == "someStuff"
19
+ end
20
+
21
+ it "handles prefixes correctly" do
22
+ "_some_stuff".camelize.should == "SomeStuff"
23
+ end
24
+ end
25
+
26
+ describe '#dasherize' do
27
+ it "converts camelized strings into dashed" do
28
+ "SomeStuff".dasherize.should == "some-stuff"
29
+ end
30
+
31
+ it "converts underscored strings into dashed as well" do
32
+ "some_stuff".dasherize.should == "some-stuff"
33
+ end
34
+ end
35
+
36
+ describe '#capitalize' do
37
+ it "capitalizes strings" do
38
+ "some stuff".capitalize.should == "Some stuff"
39
+ end
40
+ end
41
+
42
+ describe '#starts_with?' do
43
+ it "returns true if a string starts with the substring" do
44
+ "some stuff".starts_with?("some").should == true
45
+ end
46
+
47
+ it "returns false if the string doesn't start with the substring" do
48
+ "some stuff".starts_with?("non matching").should == false
49
+ end
50
+ end
51
+
52
+ describe '#ends_with?' do
53
+ it "returns true if the string ends with the given substring" do
54
+ "some stuff".ends_with?("stuff").should == true
55
+ end
56
+
57
+ it "returns false if the string doesn't end with the substring" do
58
+ "some stuff".ends_with?("non matching").should == false
59
+ end
60
+ end
61
+
62
+ describe '#blank?' do
63
+ it "returns true if the string is empty" do
64
+ ''.blank?.should == true
65
+ end
66
+
67
+ it "returns true if the string has only white spaces" do
68
+ " \n\t\r ".blank?.should == true
69
+ end
70
+
71
+ it "returns false if the string has non-space chars in it" do
72
+ " a ".blank?.should == false
73
+ end
74
+ end
75
+
76
+ describe '#constantize' do
77
+ it "returns an object from it's value" do
78
+ "UnderOs::App".constantize.should == UnderOs::App
79
+ end
80
+
81
+ it "raises an error if the constant is missing" do
82
+ -> {
83
+ "Something::Totally::Bogus".constantize
84
+ }.should.raise(NameError)
85
+ end
86
+ end
87
+
88
+ describe '#to_data' do
89
+ before do
90
+ @data = "ohai there".to_data
91
+ end
92
+
93
+ it "converts the string into a data object" do
94
+ @data.is_a?(NSData).should == true
95
+ end
96
+
97
+ it "converts it into data with correct content" do
98
+ @data.to_s.should == "ohai there"
99
+ end
100
+ end
101
+ end