Ruby metaprogramming - declaring "properties" on a class
Rather than access the possibly uninitialized @permissions instance variable inside my_property, use your wrapper method permissions and put the initialization logic in there. Also use Hash.new to save you the ||= statements. Also, the name list should be a Set, IMHO:

def permissions
  @permissions ||= Hash.new { |h,k| h[k] = Hash.new { |h,k| h[k] = Set.new }}
end


That way you can simply call

permissions[permission][level].add


without bothering if the intermediate hashes and sets have been initialized

Some other thoughts:


The second half of your my_property method is only about updating the access methods. This should be a separate method.
You don't use @perm_methods at all, you can remove it.
Use map(&amp;:to_sym) (or even better, don't create the temporary string array in the first place, it's not shorter!).
Don't use to_sym on the first argument to define_method, it shouldn't be necessary.
The min_level part can be improved in style and efficiency. You have at least two options here to get all the affected levels:


Use array slicing: access_levels[access_levels.index(level)..-1]
Use drop_while: access_levels.drop_while { |level| level != min_level }



After cleaning this up a bit, I came around with the following (untested) code:

require 'set'

class ResourceBase
  class &lt;&lt; self
    def my_property(name, access)
      access_levels = [ :all, :owner, :admin ]
      puts "#{name}: #{access}"

      access.each do |perm, min_level|
        access_levels.drop_while { |level| level != min_level }.each do |level|
          permissions[perm][level].add name
        end
      end
      update_permission_methods
    end

    def update_permission_methods
      permissions.each do |name, perm|
        define_method("#{name}able_properties") { |level| perm[level] }
      end
    end

    def permissions
      @permissions ||= Hash.new { |h,k| h[k] = Hash.new { |h,k| h[k] = Set.new }}
    end
  end
end

class Resource &lt; ResourceBase
  # Levels range: all &lt; owner &lt; admin
  # Higher levels imply lower ones (i.e. admin always have owner access)
  my_property :id, :read =&gt; :admin #, :write =&gt; :none
  my_property :name, :read =&gt; :all, :write =&gt; :owner
  my_property :pin, :read =&gt; :owner, :write =&gt; :owner
end

resource = Resource.new
puts "Readable: " + resource.readable_properties(:admin).to_s
puts "Writeable: " + resource.writeable_properties(:admin).to_s