motel 0.2

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,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
+