motel 0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,109 @@
1
+ # The Location model definition
2
+ #
3
+ # Copyright (C) 2009 Mohammed Morsi <movitto@yahoo.com>
4
+ # See COPYING for the License of this software
5
+
6
+ require 'motel/models/movement_strategy'
7
+
8
+ module Motel
9
+ module Models
10
+
11
+ # A Location defines an optional parent location and the x,y,z
12
+ # cartesian coordinates of the location relative to that parent.
13
+ # If parent is not specified x,y,z are ignored and this location
14
+ # is assumed to be the 'center' of the system to which it belongs
15
+ # Also is related to a movable object defining the parameters
16
+ # of the locations movement
17
+ class Location < ActiveRecord::Base
18
+ # a location may have a parent and/or act as a parent to others
19
+ belongs_to :location, :foreign_key => :parent_id
20
+ has_many :locations, :foreign_key => :parent_id, :dependent => :destroy
21
+
22
+ belongs_to :movement_strategy
23
+
24
+ # a generic association which this location can belong to
25
+ belongs_to :entity, :polymorphic => true
26
+ #validates_presense_of [ :entity_type, :entity_id ]
27
+
28
+ # FIXME add optional remote_location_server field
29
+
30
+ alias :parent :location
31
+ alias :parent= :location=
32
+ alias :children :locations
33
+ alias :children= :locations=
34
+
35
+ # return this location's root location
36
+ def root
37
+ return self if parent.nil?
38
+ return parent.root
39
+ end
40
+
41
+ # traverse all chilren recursively, calling block for each
42
+ def traverse_descendants(&bl)
43
+ children.each { |child|
44
+ bl.call child
45
+ child.traverse_descendants &bl
46
+ }
47
+ end
48
+
49
+ # default to the stopped movement strategy if not set on validation
50
+ before_validation :default_movement_strategy
51
+ def default_movement_strategy
52
+ self.movement_strategy = MovementStrategy.stopped if self.movement_strategy.nil?
53
+ end
54
+
55
+ public
56
+ validates_presence_of :movement_strategy
57
+
58
+ validates_presence_of [:x, :y, :z],
59
+ :unless => Proc.new { |location| location.location.nil? }
60
+
61
+ validates_presence_of :location,
62
+ :unless => Proc.new { |location| location.x.nil? &&
63
+ location.y.nil? &&
64
+ location.z.nil? }
65
+
66
+ public
67
+
68
+ # return non-nil attributes in hash
69
+ def to_h
70
+ result = {}
71
+ #result[:id] = id unless id.nil?
72
+ result[:parent_id] = parent_id unless parent_id.nil?
73
+ result[:x] = x unless x.nil?
74
+ result[:y] = y unless y.nil?
75
+ result[:z] = z unless z.nil?
76
+ return result
77
+ end
78
+
79
+ # convert location to a string
80
+ def to_s
81
+ "id:#{id}; parent_id:#{parent_id}; parent: #{parent.nil? ? "nil" : "notnil"}; entity type: #{entity_type}; x:#{x}; y:#{y}; z:#{z}; " +
82
+ "movement_strategy:#{movement_strategy.to_s}; children:#{locations.size}"
83
+ end
84
+
85
+ # return sum of the x values of this location and all its parents,
86
+ # eg the absolute 'x' of the location
87
+ def total_x
88
+ return 0 if location.nil?
89
+ return location.total_x + x
90
+ end
91
+
92
+ # return sum of the y values of this location and all its parents
93
+ # eg the absolute 'y' of the location
94
+ def total_y
95
+ return 0 if location.nil?
96
+ return location.total_y + y
97
+ end
98
+
99
+ # return sum of the z values of this location and all its parents
100
+ # eg the absolute 'z' of the location
101
+ def total_z
102
+ return 0 if location.nil?
103
+ return location.total_z + z
104
+ end
105
+
106
+ end
107
+
108
+ end # module Models
109
+ end # module Motel
@@ -0,0 +1,82 @@
1
+ # The MovementStrategy model definition
2
+ #
3
+ # Copyright (C) 2009 Mohammed Morsi <movitto@yahoo.com>
4
+ # See COPYING for the License of this software
5
+
6
+ require 'motel/common'
7
+ require 'motel/models/location'
8
+
9
+ module Motel
10
+ module Models
11
+
12
+ # MovementStrategy subclasses define the rules and params which
13
+ # a location changes its position.
14
+ class MovementStrategy < ActiveRecord::Base
15
+ # strategy is associated with location to move it
16
+ has_many :locations, :dependent => :destroy
17
+
18
+ # callbacks invoked when this object is moved
19
+ attr_accessor :movement_callbacks
20
+
21
+ # every movement strategy needs a type
22
+ validates_presence_of :type
23
+
24
+ # as more types are supported, add them here
25
+ validates_inclusion_of :type,
26
+ :in => %w( Stopped Linear Elliptical )
27
+
28
+ # step delay is recommended number of seconds
29
+ # a runner should sleep for between move invocations
30
+ validates_presence_of :step_delay
31
+
32
+ # default step_delay if not set
33
+ before_validation :default_step_delay
34
+ def default_step_delay
35
+ self.step_delay = 5 if step_delay.nil?
36
+ end
37
+
38
+ # use after_initialize instead of initialize
39
+ # http://blog.dalethatcher.com/2008/03/rails-dont-override-initialize-on.html
40
+ def after_initialize
41
+ @movement_callbacks = []
42
+ end
43
+
44
+ # default movement strategy is to do nothing
45
+ def move(location, elapsed_seconds)
46
+ end
47
+
48
+ # retreive the 'stopped' movement strategy
49
+ def self.stopped
50
+ ms = MovementStrategy.find(:first, :conditions => "type = 'Stopped'")
51
+ ms.nil? ? Stopped.new(:step_delay => 5) : ms
52
+ end
53
+
54
+ # return subclass corresponding to specified strategy type
55
+ def self.factory(strategy_type)
56
+ return MovementStrategy if strategy_type.nil?
57
+
58
+ if strategy_type.downcase == "stopped" || strategy_type == "Motel::Models::Stopped"
59
+ return Stopped
60
+ elsif strategy_type.downcase == "linear" || strategy_type == "Motel::Models::Linear"
61
+ return Linear
62
+ elsif strategy_type.downcase == "elliptical" || strategy_type == "Motel::Models::Elliptical"
63
+ return Elliptical
64
+ end
65
+
66
+ return MovementStrategy
67
+ end
68
+
69
+ # convert movement strategy to a hash
70
+ def to_h
71
+ {}
72
+ end
73
+
74
+ # convert movement strategy to a string
75
+ def to_s
76
+ "id:#{id}; type:#{self.class}" # XXX should be self.type but ruby will complain, this works for now
77
+ end
78
+
79
+ end
80
+
81
+ end # module Models
82
+ end # module Motel
@@ -0,0 +1,16 @@
1
+ # The Stopped MovementStrategy model definition
2
+ #
3
+ # Copyright (C) 2009 Mohammed Morsi <movitto@yahoo.com>
4
+ # See COPYING for the License of this software
5
+
6
+ require 'motel/models/movement_strategy'
7
+
8
+ module Motel
9
+ module Models
10
+
11
+ # Stopped is the default MovementStrategy which does nothing
12
+ class Stopped < MovementStrategy
13
+ end
14
+
15
+ end # module Models
16
+ end # module Motel
@@ -0,0 +1,135 @@
1
+ # Defines the LocationRunner and Runner classes, core to the motel engine,
2
+ # and is responsible for managing locations and moving them according to
3
+ # their corresponding movement_strategies
4
+ #
5
+ # Copyright (C) 2009 Mohammed Morsi <movitto@yahoo.com>
6
+ # See COPYING for the License of this software
7
+
8
+ module Motel
9
+
10
+ # A LocationRunner runs a Location by moving it via
11
+ # its associated MovementStrategy.
12
+ class LocationRunner
13
+ attr_reader :location
14
+ attr_reader :run_thread
15
+
16
+ def initialize(location)
17
+ return if location.nil? || location.id.nil? || location.class != Location
18
+
19
+ @terminate = false
20
+ @location = location
21
+ @location_lock = Mutex.new
22
+ Logger.info " running location " + location.to_s
23
+
24
+ # TODO at some point use a thread pool approach
25
+ @run_thread = Thread.new { run_move_cycle(location) }
26
+ end
27
+
28
+ # Terminate run cycle, stopping location movement.
29
+ # After this the runner cannot be used again
30
+ def terminate
31
+ @terminate = true
32
+ @location_lock.synchronize{
33
+ unless run_thread.nil?
34
+ @run_thread.join
35
+ @run_thread = nil
36
+ end
37
+ }
38
+ end
39
+
40
+ private
41
+
42
+ # Launched in a seperate thread, run_move_cycle
43
+ # runs a location according to its associated
44
+ # movement strategy with a specified delay between
45
+ # runs. Terminated when the Runner.terminate
46
+ # method is invoked
47
+ def run_move_cycle(location)
48
+ # track the time between runs
49
+ start_time = Time.now
50
+
51
+ # run until we are instructed not to
52
+ until(@terminate) do
53
+ Logger.debug "runner invoking move on location " + location.to_s + " via " + location.movement_strategy.type.to_s + " movement strategy"
54
+
55
+ ## perform the actual move
56
+ location.movement_strategy.move location, start_time - Time.now
57
+ start_time = Time.now
58
+
59
+ # TODO see if we've actually moved b4 invoking callbacks
60
+ location.movement_strategy.movement_callbacks.each { |callback|
61
+ callback.call(location)
62
+ }
63
+
64
+ ## delay as long as the strategy tells us to
65
+ sleep location.movement_strategy.step_delay
66
+ end
67
+ end
68
+
69
+ end
70
+
71
+
72
+ # A Runner manages groups of LocationRunner instances
73
+ # Restricts use to a single instance, obtained via the
74
+ # 'get' method
75
+ class Runner
76
+
77
+ private
78
+
79
+ # Default class constructor
80
+ # private as runner should be accessed through singleton 'get' method
81
+ def initialize
82
+ # set to true to terminate the runner
83
+ @terminate = false
84
+
85
+ # locations is a list of instances of LocationRunner to manage
86
+ @location_runners = []
87
+ @runners_lock = Mutex.new
88
+ end
89
+
90
+ public
91
+
92
+ # singleton getter
93
+ def self.get
94
+ @@singleton_instance = Runner.new if !defined? @@singleton_instance || @@singleton_instance.nil?
95
+ return @@singleton_instance
96
+ end
97
+
98
+ attr_reader :location_runners
99
+
100
+ # helper method, return all locations associated w/ runners
101
+ def locations
102
+ [] if @location_runners.nil? || @location_runners.size == 0
103
+ @location_runners.collect { |runner| runner.location }
104
+ end
105
+
106
+ # clear all location_runners
107
+ def clear
108
+ @location_runners.clear
109
+ end
110
+
111
+ # Terminate all run cycles, stopping all location movements.
112
+ # After this the runner cannot be used again
113
+ def terminate
114
+ @terminate = true
115
+ @runners_lock.synchronize{
116
+ @location_runners.each { |runner|
117
+ runner.terminate
118
+ }
119
+ }
120
+ end
121
+
122
+ # Run a location using this runner. If the location
123
+ # is already being run by this runner, do nothing.
124
+ # A new thread will be launched to run the actual move cycle
125
+ def run(location)
126
+ @runners_lock.synchronize{
127
+ unless @location_runners.find { |l| l.location.id == location.id}
128
+ @location_runners.push LocationRunner.new(location)
129
+ end
130
+ }
131
+ end
132
+
133
+ end
134
+
135
+ end # module motel
@@ -0,0 +1,58 @@
1
+ #
2
+ # $Id: semaphore.rb,v 1.2 2003/03/15 20:10:10 fukumoto Exp $
3
+ #
4
+ # Copied unmodified from:
5
+ # http://www.imasy.or.jp/~fukumoto/ruby/semaphore.rb
6
+ # Originally licensed under The Ruby License:
7
+ # http://raa.ruby-lang.org/project/semaphore/
8
+
9
+ class CountingSemaphore
10
+
11
+ def initialize(initvalue = 0)
12
+ @counter = initvalue
13
+ @waiting_list = []
14
+ end
15
+
16
+ def wait
17
+ Thread.critical = true
18
+ if (@counter -= 1) < 0
19
+ @waiting_list.push(Thread.current)
20
+ Thread.stop
21
+ end
22
+ self
23
+ ensure
24
+ Thread.critical = false
25
+ end
26
+
27
+ def signal
28
+ Thread.critical = true
29
+ begin
30
+ if (@counter += 1) <= 0
31
+ t = @waiting_list.shift
32
+ t.wakeup if t
33
+ end
34
+ rescue ThreadError
35
+ retry
36
+ end
37
+ self
38
+ ensure
39
+ Thread.critical = false
40
+ end
41
+
42
+ alias down wait
43
+ alias up signal
44
+ alias P wait
45
+ alias V signal
46
+
47
+ def exclusive
48
+ wait
49
+ yield
50
+ ensure
51
+ signal
52
+ end
53
+
54
+ alias synchronize exclusive
55
+
56
+ end
57
+
58
+ Semaphore = CountingSemaphore
data/lib/motel.rb ADDED
@@ -0,0 +1,13 @@
1
+ # include all motel modules
2
+ #
3
+ # Copyright (C) 2009 Mohammed Morsi <movitto@yahoo.com>
4
+ # See COPYING for the License of this software
5
+
6
+ lib = File.dirname(__FILE__)
7
+
8
+ require lib + '/motel/conf'
9
+ require lib + '/motel/runner'
10
+ require lib + '/motel/loader'
11
+ require lib + '/motel/simrpc'
12
+
13
+ Dir[lib + '/motel/models/*.rb'].each { |model| require model }
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: motel
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.2"
5
+ platform: ruby
6
+ authors:
7
+ - Mohammed Morsi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-09-04 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activerecord
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 2.1.1
24
+ version:
25
+ description: Motel is a library to track and move the locations of objects in a 3D environment.
26
+ email: movitto@yahoo.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README
33
+ files:
34
+ - conf/amqp.yml
35
+ - conf/database.yml
36
+ - db/migrate/001_create_locations_and_movement_strategies.rb
37
+ - db/migrate/002_create_linear_movement_strategy.rb
38
+ - db/migrate/003_create_elliptical_movement_strategy.rb
39
+ - lib/motel/models/location.rb
40
+ - lib/motel/models/movement_strategy.rb
41
+ - lib/motel/models/stopped.rb
42
+ - lib/motel/models/linear.rb
43
+ - lib/motel/models/elliptical.rb
44
+ - lib/motel/common.rb
45
+ - lib/motel/loader.rb
46
+ - lib/motel/runner.rb
47
+ - lib/motel/semaphore.rb
48
+ - lib/motel.rb
49
+ - LICENSE
50
+ - COPYING
51
+ - README
52
+ has_rdoc: true
53
+ homepage: http://morsi.org/projects/motel
54
+ licenses: []
55
+
56
+ post_install_message:
57
+ rdoc_options:
58
+ - --inline-source
59
+ - --charset=UTF-8
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ version:
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 1.3.1
73
+ version:
74
+ requirements: []
75
+
76
+ rubyforge_project:
77
+ rubygems_version: 1.3.5
78
+ signing_key:
79
+ specification_version: 3
80
+ summary: Motel is a library to track and move the locations of objects in a 3D environment.
81
+ test_files: []
82
+