under-os-core 1.4.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,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