machineshop 0.0.1
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.
- checksums.yaml +7 -0
- data/.idea/.name +1 -0
- data/.idea/.rakeTasks +7 -0
- data/.idea/compiler.xml +23 -0
- data/.idea/copyright/profiles_settings.xml +5 -0
- data/.idea/encodings.xml +5 -0
- data/.idea/inspectionProfiles/Project_Default.xml +7 -0
- data/.idea/inspectionProfiles/profiles_settings.xml +7 -0
- data/.idea/machineshop.iml +194 -0
- data/.idea/misc.xml +5 -0
- data/.idea/modules.xml +9 -0
- data/.idea/scopes/scope_settings.xml +5 -0
- data/.idea/vcs.xml +7 -0
- data/.idea/workspace.xml +722 -0
- data/Gemfile +8 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/Rakefile +8 -0
- data/doc.txt +50 -0
- data/lib/machineshop.rb +234 -0
- data/lib/machineshop/api_operations/create.rb +17 -0
- data/lib/machineshop/api_operations/delete.rb +11 -0
- data/lib/machineshop/api_operations/list.rb +16 -0
- data/lib/machineshop/api_operations/update.rb +17 -0
- data/lib/machineshop/api_resource.rb +35 -0
- data/lib/machineshop/configuration.rb +11 -0
- data/lib/machineshop/customer.rb +9 -0
- data/lib/machineshop/database.rb +112 -0
- data/lib/machineshop/device.rb +30 -0
- data/lib/machineshop/device_instance.rb +30 -0
- data/lib/machineshop/errors/api_error.rb +4 -0
- data/lib/machineshop/errors/authentication_error.rb +4 -0
- data/lib/machineshop/errors/database_error.rb +5 -0
- data/lib/machineshop/errors/invalid_request_error.rb +10 -0
- data/lib/machineshop/errors/machineshop_error.rb +20 -0
- data/lib/machineshop/json.rb +21 -0
- data/lib/machineshop/machineshop_cache.rb +49 -0
- data/lib/machineshop/machineshop_object.rb +164 -0
- data/lib/machineshop/mapping.rb +34 -0
- data/lib/machineshop/meter.rb +12 -0
- data/lib/machineshop/models/people.rb +11 -0
- data/lib/machineshop/report.rb +11 -0
- data/lib/machineshop/rule.rb +58 -0
- data/lib/machineshop/user.rb +43 -0
- data/lib/machineshop/util.rb +115 -0
- data/lib/machineshop/utility.rb +30 -0
- data/lib/machineshop/version.rb +3 -0
- data/machineshop.gemspec +24 -0
- data/spec/lib/api_calls_spec.rb +628 -0
- data/spec/lib/customer_spec.rb +76 -0
- data/spec/lib/device_spec.rb +179 -0
- data/spec/lib/mapping_spec.rb +64 -0
- data/spec/lib/meter_spec.rb +46 -0
- data/spec/lib/report_spec.rb +52 -0
- data/spec/lib/rule_spec.rb +117 -0
- data/spec/lib/user_spec.rb +53 -0
- data/spec/spec_helper.rb +3 -0
- metadata +184 -0
| @@ -0,0 +1,112 @@ | |
| 1 | 
            +
            module MachineShop
         | 
| 2 | 
            +
            =begin
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              require 'machineshop/errors/machineshop_error'
         | 
| 5 | 
            +
              require 'machineshop/errors/api_error'
         | 
| 6 | 
            +
              require 'machineshop/errors/database_error'
         | 
| 7 | 
            +
              require 'mysql'
         | 
| 8 | 
            +
              require 'active_record'
         | 
| 9 | 
            +
              require 'machineshop/configuration'
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              class Database < Configuration
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                attr_accessor :con, :rs,:db_connected
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def initialize()
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                @db_connected=true
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                begin
         | 
| 20 | 
            +
                @@con = Mysql.new(MachineShop.configuration.db_host,MachineShop.configuration.db_username,MachineShop.configuration.db_password,MachineShop.configuration.db_name)
         | 
| 21 | 
            +
             | 
| 22 | 
            +
             @act = ActiveRecord::Base.establish_connection(
         | 
| 23 | 
            +
              adapter:  'mysql', # or 'postgresql' or 'sqlite3'
         | 
| 24 | 
            +
              host:     MachineShop.configuration.db_host,
         | 
| 25 | 
            +
              # database: MachineShop.configuration.db_name,
         | 
| 26 | 
            +
              database: "machineshop",
         | 
| 27 | 
            +
              username: MachineShop.configuration.db_username,
         | 
| 28 | 
            +
              # password: MachineShop.configuration.db_password
         | 
| 29 | 
            +
              password: "root"
         | 
| 30 | 
            +
              )
         | 
| 31 | 
            +
             | 
| 32 | 
            +
             ActiveRecord::Migration.class_eval do
         | 
| 33 | 
            +
              create_table :devices do |t|
         | 
| 34 | 
            +
                    t.string :_id
         | 
| 35 | 
            +
                    t.string :active
         | 
| 36 | 
            +
                    t.string :created_at
         | 
| 37 | 
            +
                    t.string :deleted_at
         | 
| 38 | 
            +
                    t.string :exe_path
         | 
| 39 | 
            +
                    t.string :image_url
         | 
| 40 | 
            +
                    t.string :init_cmd
         | 
| 41 | 
            +
                    t.string :init_params
         | 
| 42 | 
            +
                    t.string :last_known_translator_port
         | 
| 43 | 
            +
                    t.string :long_description
         | 
| 44 | 
            +
                    t.string :manual_url
         | 
| 45 | 
            +
                    t.string :manufacturer
         | 
| 46 | 
            +
                    t.string :model
         | 
| 47 | 
            +
                    t.string :name
         | 
| 48 | 
            +
                    t.string :rule_ids
         | 
| 49 | 
            +
                    t.string :sample_data
         | 
| 50 | 
            +
                    t.string :software
         | 
| 51 | 
            +
                    t.string :tag_ids
         | 
| 52 | 
            +
                    t.string :translator
         | 
| 53 | 
            +
                    t.string :type
         | 
| 54 | 
            +
                    t.string :unit_price
         | 
| 55 | 
            +
                    t.string :updated_at
         | 
| 56 | 
            +
                    t.string :user_id
         | 
| 57 | 
            +
               end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
               create_table :people do |t|
         | 
| 60 | 
            +
                  t.string :first_name
         | 
| 61 | 
            +
                  t.string :last_name
         | 
| 62 | 
            +
                  t.string :short_name
         | 
| 63 | 
            +
               end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
               create_table :tags do |t|
         | 
| 66 | 
            +
                  t.string :tags
         | 
| 67 | 
            +
               end 
         | 
| 68 | 
            +
            end
         | 
| 69 | 
            +
            # puts "act is #{@act.inspect}"
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                  
         | 
| 72 | 
            +
                rescue Exception => e
         | 
| 73 | 
            +
                  @db_connected=false
         | 
| 74 | 
            +
                 return @db_connected
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                raise DatabaseError.new("Connection to Database refused")
         | 
| 77 | 
            +
              end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                @rs = @@con.query('select url from endpoints')
         | 
| 80 | 
            +
                @rs.each_hash { |h| puts h['url']}
         | 
| 81 | 
            +
              end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
              # def database_error(error)
         | 
| 84 | 
            +
              #   DatabaseError.new(error)
         | 
| 85 | 
            +
              # end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
             | 
| 88 | 
            +
             | 
| 89 | 
            +
              def self.insert(user_id, table_name, data={})
         | 
| 90 | 
            +
                @rs = @@con.query("INSERT INTO #{table_name} (`id`, `url`) VALUES (NULL, '#{data}')")
         | 
| 91 | 
            +
            puts "inserted #{@rs.inspect}"
         | 
| 92 | 
            +
              end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
             | 
| 95 | 
            +
              def self.get(user_id,table_name,filter={})
         | 
| 96 | 
            +
                @rs = @@con.query("SELECT * FROM #{table_name}")
         | 
| 97 | 
            +
                puts "get  #{@rs.inspect}"
         | 
| 98 | 
            +
              end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
              def self.serialize_data(data)
         | 
| 101 | 
            +
                Marshal.dump(data)
         | 
| 102 | 
            +
              end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
            end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
            end
         | 
| 107 | 
            +
            =end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
            end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
            # Database.new
         | 
| 112 | 
            +
            # Database.insert('endpoints',"/user/devices/id")
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            module MachineShop
         | 
| 2 | 
            +
              class Device < APIResource
         | 
| 3 | 
            +
                include MachineShop::APIOperations::List
         | 
| 4 | 
            +
                include MachineShop::APIOperations::Create
         | 
| 5 | 
            +
                include MachineShop::APIOperations::Delete
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                # Specific API calls
         | 
| 8 | 
            +
                def payload_fields(params=nil)
         | 
| 9 | 
            +
                  MachineShop.get(payload_fields_url, @auth_token, params)
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def create_instance(params)
         | 
| 13 | 
            +
                  params.merge!({:device_id => self.id})
         | 
| 14 | 
            +
                  DeviceInstance.create(params, @auth_token)
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def instances(params={})
         | 
| 18 | 
            +
                  params.merge!({:device_id => self.id})
         | 
| 19 | 
            +
                  DeviceInstance.all(params, @auth_token)
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                private
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                def payload_fields_url
         | 
| 25 | 
            +
                  url + '/payload_fields'
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
             | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            module MachineShop
         | 
| 2 | 
            +
              class DeviceInstance < APIResource
         | 
| 3 | 
            +
                include MachineShop::APIOperations::List
         | 
| 4 | 
            +
                include MachineShop::APIOperations::Create
         | 
| 5 | 
            +
                include MachineShop::APIOperations::Delete
         | 
| 6 | 
            +
                
         | 
| 7 | 
            +
                # Specific API calls
         | 
| 8 | 
            +
                
         | 
| 9 | 
            +
                def report_count(params)      
         | 
| 10 | 
            +
                  MachineShop.get(report_count_url, @auth_token, params)
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
                
         | 
| 13 | 
            +
                def reports(filters={})
         | 
| 14 | 
            +
                  filters.merge!(:device_instance_id => self.id)
         | 
| 15 | 
            +
                  MachineShop::Report.all(filters, @auth_token)
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
                
         | 
| 18 | 
            +
                def meters(filters={})
         | 
| 19 | 
            +
                  filters.merge!(:device_instance_id => self.id)
         | 
| 20 | 
            +
                  MachineShop::Meter.all(filters, @auth_token)
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
                
         | 
| 23 | 
            +
                private
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def report_count_url
         | 
| 26 | 
            +
                  url + '/report_count'
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            module MachineShop
         | 
| 2 | 
            +
              class MachineShopError < StandardError
         | 
| 3 | 
            +
                attr_reader :message
         | 
| 4 | 
            +
                attr_reader :http_status
         | 
| 5 | 
            +
                attr_reader :http_body
         | 
| 6 | 
            +
                attr_reader :json_body
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def initialize(message=nil, http_status=nil, http_body=nil, json_body=nil)
         | 
| 9 | 
            +
                  @message = message
         | 
| 10 | 
            +
                  @http_status = http_status
         | 
| 11 | 
            +
                  @http_body = http_body
         | 
| 12 | 
            +
                  @json_body = json_body
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def to_s          
         | 
| 16 | 
            +
                  status_string = @http_status.nil? ? "" : "(Status #{@http_status}) "
         | 
| 17 | 
            +
                  "#{status_string}#{@message}"
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
            end
         | 
| @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            module MachineShop
         | 
| 2 | 
            +
              module JSON
         | 
| 3 | 
            +
                if MultiJson.respond_to?(:dump)
         | 
| 4 | 
            +
                  def self.dump(*args)
         | 
| 5 | 
            +
                    MultiJson.dump(*args)
         | 
| 6 | 
            +
                  end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  def self.load(*args)
         | 
| 9 | 
            +
                    MultiJson.load(*args)
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
                else
         | 
| 12 | 
            +
                  def self.dump(*args)
         | 
| 13 | 
            +
                    MultiJson.encode(*args)
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def self.load(*args)
         | 
| 17 | 
            +
                    MultiJson.decode(*args)
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
            end
         | 
| @@ -0,0 +1,49 @@ | |
| 1 | 
            +
            module MachineShop
         | 
| 2 | 
            +
              class MachineshopCache
         | 
| 3 | 
            +
                #require 'Rails'
         | 
| 4 | 
            +
                #require 'active_support/cache'
         | 
| 5 | 
            +
                require 'active_record'
         | 
| 6 | 
            +
                cache = ActiveSupport::Cache.lookup_cache(:memory_store)
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                Rails.cache.class.class_eval do
         | 
| 9 | 
            +
                  attr_accessor :enabled
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def read_with_enabled(*args, &block)
         | 
| 12 | 
            +
                    enabled ? read_without_enabled( *args, &block) : nil
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  alias_method_chain :read, :enabled
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                if File.basename($0) == "rake" && ARGV.include?("db:migrate")
         | 
| 20 | 
            +
                  Rails.cache.enabled = false
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                else
         | 
| 23 | 
            +
                  Rails.cache.enabled = true
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              describe "Rails.cache" do
         | 
| 29 | 
            +
                it 'can be disabled and enabled' do
         | 
| 30 | 
            +
                  Rails.cache.enabled = true
         | 
| 31 | 
            +
                  Rails.cache.enabled.should be_true
         | 
| 32 | 
            +
                  Rails.cache.write("foobar","foo")
         | 
| 33 | 
            +
                  Rails.cache.read("foobar").should == "foo"
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  Rails.cache.enabled = false
         | 
| 36 | 
            +
                  Rails.cache.enabled.should be_false
         | 
| 37 | 
            +
                  Rails.cache.write("foobar","foo")
         | 
| 38 | 
            +
                  Rails.cache.read("foobar").shoule be_nil
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  Rails.cache.enabled = true
         | 
| 41 | 
            +
                  Rails.cache.read("foobar").should == "foo"
         | 
| 42 | 
            +
             | 
| 43 | 
            +
             | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
             | 
| 49 | 
            +
            end
         | 
| @@ -0,0 +1,164 @@ | |
| 1 | 
            +
            module MachineShop
         | 
| 2 | 
            +
              class MachineShopObject
         | 
| 3 | 
            +
                include Enumerable
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                attr_accessor :auth_token
         | 
| 6 | 
            +
                @@permanent_attributes = Set.new([:auth_token, :id])
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                # The default :id method is deprecated and isn't useful to us
         | 
| 9 | 
            +
                if method_defined?(:id)
         | 
| 10 | 
            +
                  undef :id
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def initialize(id=nil, auth_token=nil)
         | 
| 14 | 
            +
                  # parameter overloading!
         | 
| 15 | 
            +
                  if id.kind_of?(Hash)
         | 
| 16 | 
            +
                    @retrieve_options = id.dup
         | 
| 17 | 
            +
                    @retrieve_options.delete(:id)
         | 
| 18 | 
            +
                    id = id[:id] ? id[:id] : id[:_id]
         | 
| 19 | 
            +
                  else
         | 
| 20 | 
            +
                    @retrieve_options = {}
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  @auth_token = auth_token
         | 
| 24 | 
            +
                  @values = {}
         | 
| 25 | 
            +
                  # This really belongs in APIResource, but not putting it there allows us
         | 
| 26 | 
            +
                  # to have a unified inspect method
         | 
| 27 | 
            +
                  @unsaved_values = Set.new
         | 
| 28 | 
            +
                  @transient_values = Set.new
         | 
| 29 | 
            +
                  self.id = id if id
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                def self.construct_from(values, auth_token=nil)
         | 
| 33 | 
            +
                  values[:id] = values[:_id] if values[:_id]
         | 
| 34 | 
            +
                  obj = self.new(values[:id], auth_token)
         | 
| 35 | 
            +
                  obj.refresh_from(values, auth_token)
         | 
| 36 | 
            +
                  obj
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def to_s(*args)
         | 
| 40 | 
            +
                  MachineShop::JSON.dump(@values, :pretty => true)
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                def inspect()
         | 
| 44 | 
            +
                  id_string = (self.respond_to?(:id) && !self.id.nil?) ? " id=#{self.id}" : ""
         | 
| 45 | 
            +
                  "#<#{self.class}:0x#{self.object_id.to_s(16)}#{id_string}> JSON: " + MachineShop::JSON.dump(@values, :pretty => true)
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                def refresh_from(values, auth_token, partial=false)
         | 
| 49 | 
            +
                  @auth_token = auth_token
         | 
| 50 | 
            +
                  case values
         | 
| 51 | 
            +
                  when Array
         | 
| 52 | 
            +
                    values = values[0]
         | 
| 53 | 
            +
                  else
         | 
| 54 | 
            +
                    #do nothing
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
                  values[:id] = values[:_id] if values[:_id]
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                  removed = partial ? Set.new : Set.new(@values.keys - values.keys)
         | 
| 59 | 
            +
                  added = Set.new(values.keys - @values.keys)
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  instance_eval do
         | 
| 62 | 
            +
                    remove_accessors(removed)
         | 
| 63 | 
            +
                    add_accessors(added)
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
                  removed.each do |k|
         | 
| 66 | 
            +
                    @values.delete(k)
         | 
| 67 | 
            +
                    @transient_values.add(k)
         | 
| 68 | 
            +
                    @unsaved_values.delete(k)
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
                  values.each do |k, v|
         | 
| 71 | 
            +
                    @values[k] = Util.convert_to_machineshop_object(v, auth_token)
         | 
| 72 | 
            +
                    @transient_values.delete(k)
         | 
| 73 | 
            +
                    @unsaved_values.delete(k)
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
                end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                def [](k)
         | 
| 78 | 
            +
                  k = k.to_sym if k.kind_of?(String)
         | 
| 79 | 
            +
                  @values[k]
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                def []=(k, v)
         | 
| 83 | 
            +
                  send(:"#{k}=", v)
         | 
| 84 | 
            +
                end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                def keys
         | 
| 87 | 
            +
                  @values.keys
         | 
| 88 | 
            +
                end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                def values
         | 
| 91 | 
            +
                  @values.values
         | 
| 92 | 
            +
                end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                def to_json(*a)
         | 
| 95 | 
            +
                  MachineShop::JSON.dump(@values)
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                def as_json(*a)
         | 
| 99 | 
            +
                  @values.as_json(*a)
         | 
| 100 | 
            +
                end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                def to_hash
         | 
| 103 | 
            +
                  @values
         | 
| 104 | 
            +
                end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                def each(&blk)
         | 
| 107 | 
            +
                  @values.each(&blk)
         | 
| 108 | 
            +
                end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                protected
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                def metaclass
         | 
| 113 | 
            +
                  class << self; self; end
         | 
| 114 | 
            +
                end
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                def remove_accessors(keys)
         | 
| 117 | 
            +
                  metaclass.instance_eval do
         | 
| 118 | 
            +
                    keys.each do |k|
         | 
| 119 | 
            +
                      next if @@permanent_attributes.include?(k)
         | 
| 120 | 
            +
                      k_eq = :"#{k}="
         | 
| 121 | 
            +
                      remove_method(k) if method_defined?(k)
         | 
| 122 | 
            +
                      remove_method(k_eq) if method_defined?(k_eq)
         | 
| 123 | 
            +
                    end
         | 
| 124 | 
            +
                  end
         | 
| 125 | 
            +
                end
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                def add_accessors(keys)
         | 
| 128 | 
            +
                  metaclass.instance_eval do
         | 
| 129 | 
            +
                    keys.each do |k|
         | 
| 130 | 
            +
                      next if @@permanent_attributes.include?(k)
         | 
| 131 | 
            +
                      k_eq = :"#{k}="
         | 
| 132 | 
            +
                      define_method(k) { @values[k] }
         | 
| 133 | 
            +
                      define_method(k_eq) do |v|
         | 
| 134 | 
            +
                        @values[k] = v
         | 
| 135 | 
            +
                        @unsaved_values.add(k)
         | 
| 136 | 
            +
                      end
         | 
| 137 | 
            +
                    end
         | 
| 138 | 
            +
                  end
         | 
| 139 | 
            +
                end
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                def method_missing(name, *args)
         | 
| 142 | 
            +
                  # TODO: only allow setting in updateable classes.
         | 
| 143 | 
            +
                  if name.to_s.end_with?('=')
         | 
| 144 | 
            +
                    attr = name.to_s[0...-1].to_sym
         | 
| 145 | 
            +
                    @values[attr] = args[0]
         | 
| 146 | 
            +
                    @unsaved_values.add(attr)
         | 
| 147 | 
            +
                    add_accessors([attr])
         | 
| 148 | 
            +
                    return
         | 
| 149 | 
            +
                  else
         | 
| 150 | 
            +
                    return @values[name] if @values.has_key?(name)
         | 
| 151 | 
            +
                  end
         | 
| 152 | 
            +
             | 
| 153 | 
            +
                  begin
         | 
| 154 | 
            +
                    super
         | 
| 155 | 
            +
                  rescue NoMethodError => e
         | 
| 156 | 
            +
                    if @transient_values.include?(name)
         | 
| 157 | 
            +
                      raise NoMethodError.new(e.message + ".  HINT: The '#{name}' attribute was set in the past, however.  It was then wiped when refreshing the object with the result returned by MachineShop's API, probably as a result of a save().  The attributes currently available on this object are: #{@values.keys.join(', ')}")
         | 
| 158 | 
            +
                    else
         | 
| 159 | 
            +
                      raise
         | 
| 160 | 
            +
                    end
         | 
| 161 | 
            +
                  end
         | 
| 162 | 
            +
                end
         | 
| 163 | 
            +
              end
         | 
| 164 | 
            +
            end
         |