This file is indexed.

/usr/lib/ruby/vendor_ruby/celluloid/fsm.rb is in ruby-celluloid 0.16.0-4.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
module Celluloid
  # Simple finite state machines with integrated Celluloid timeout support
  # Inspired by Erlang's gen_fsm (http://www.erlang.org/doc/man/gen_fsm.html)
  #
  # Basic usage:
  #
  #     class MyMachine
  #       include Celluloid::FSM # NOTE: this does NOT pull in the Celluloid module
  #     end
  #
  # Inside an actor:
  #
  #     #
  #     machine = MyMachine.new(current_actor)
  module FSM
    class UnattachedError < Celluloid::Error; end # Not attached to an actor

    DEFAULT_STATE = :default # Default state name unless one is explicitly set

    # Included hook to extend class methods
    def self.included(klass)
      klass.send :extend, ClassMethods
    end

    module ClassMethods
      # Obtain or set the default state
      # Passing a state name sets the default state
      def default_state(new_default = nil)
        if new_default
          @default_state = new_default.to_sym
        else
          defined?(@default_state) ? @default_state : DEFAULT_STATE
        end
      end

      # Obtain the valid states for this FSM
      def states
        @states ||= {}
      end

      # Declare an FSM state and optionally provide a callback block to fire
      # Options:
      # * to: a state or array of states this state can transition to
      def state(*args, &block)
        if args.last.is_a? Hash
          # Stringify keys :/
          options = args.pop.inject({}) { |h,(k,v)| h[k.to_s] = v; h }
        else
          options = {}
        end

        args.each do |name|
          name = name.to_sym
          default_state name if options['default']
          states[name] = State.new(name, options['to'], &block)
        end
      end
    end

    attr_reader :actor

    # Be kind and call super if you must redefine initialize
    def initialize(actor = nil)
      @state = self.class.default_state
      @delayed_transition = nil
      @actor = actor
      @actor ||= Celluloid.current_actor if Celluloid.actor?
    end

    # Obtain the current state of the FSM
    attr_reader :state

    # Attach this FSM to an actor. This allows FSMs to wait for and initiate
    # events in the context of a particular actor
    def attach(actor)
      @actor = actor
    end
    alias_method :actor=, :attach

    # Transition to another state
    # Options:
    # * delay: don't transition immediately, wait the given number of seconds.
    #          This will return a Celluloid::Timer object you can use to
    #          cancel the pending state transition.
    #
    # Note: making additional state transitions will cancel delayed transitions
    def transition(state_name, options = {})
      new_state = validate_and_sanitize_new_state(state_name)
      return unless new_state

      if handle_delayed_transitions(new_state, options[:delay])
        return @delayed_transition
      end

      transition_with_callbacks!(new_state)
    end

    # Immediate state transition with no sanity checks, or callbacks. "Dangerous!"
    def transition!(state_name)
      @state = state_name
    end

    protected

    def validate_and_sanitize_new_state(state_name)
      state_name = state_name.to_sym

      return if current_state_name == state_name

      if current_state and not current_state.valid_transition? state_name
        valid = current_state.transitions.map(&:to_s).join(", ")
        raise ArgumentError, "#{self.class} can't change state from '#{@state}' to '#{state_name}', only to: #{valid}"
      end

      new_state = states[state_name]

      unless new_state
        return if state_name == default_state
        raise ArgumentError, "invalid state for #{self.class}: #{state_name}"
      end

      new_state
    end

    def transition_with_callbacks!(state_name)
      transition! state_name.name
      state_name.call(self)
    end

    def states
      self.class.states
    end

    def default_state
      self.class.default_state
    end

    def current_state
      states[@state]
    end

    def current_state_name
      current_state && current_state.name || ''
    end

    def handle_delayed_transitions(new_state, delay)
      if delay
        raise UnattachedError, "can't delay unless attached" unless @actor
        @delayed_transition.cancel if @delayed_transition

        @delayed_transition = @actor.after(delay) do
          transition_with_callbacks!(new_state)
        end

        return @delayed_transition
      end

      if defined?(@delayed_transition) and @delayed_transition
        @delayed_transition.cancel
        @delayed_transition = nil
      end
    end

    # FSM states as declared by Celluloid::FSM.state
    class State
      attr_reader :name, :transitions

      def initialize(name, transitions = nil, &block)
        @name, @block = name, block
        @transitions = nil
        @transitions = Array(transitions).map { |t| t.to_sym } if transitions
      end

      def call(obj)
        obj.instance_eval(&@block) if @block
      end

      def valid_transition?(new_state)
        # All transitions are allowed unless expressly
        return true unless @transitions

        @transitions.include? new_state.to_sym
      end
    end
  end
end