wash

          2006年5月11日 #

          programming ruby 2nd--extending ruby 1

          1.Ruby Object? in c
          2.juke box extension
          3.memory allocation
          4.ruby type system
          5.create an exception
          6embed a ruby interpreter
          7.bridge to other language
          8.c api
          1.
          p269
          Sometimes, though, life is more complicated. Perhaps you want to define a global variable
          whose valuemust be calculated when it is accessed. You do this by defining hooked
          and virtual variables. A hooked variable is a real variable that is initialized by a named
          function when the corresponding Ruby variable is accessed. Virtual variables are similar
          but are never stored: their value purely comes from evaluating the hook function.
          See the API section that begins on page 294 for details.
          If you create a Ruby object from C and store it in a C global variable without exporting
          it to Ruby, you must at least tell the garbage collector about it, lest ye be reaped
          inadvertently.
          static VALUE obj;
          // ...
          obj = rb_ary_new();
          rb_global_variable(obj);

          posted @ 2006-06-15 14:53 wash 閱讀(261) | 評論 (0)編輯 收藏

          Primary Keys and IDs

          You may have noticed that our sample database tables all define an integer
          column called id as their primary key. This is an Active Record convention.
          “But wait!” you cry. “Shouldn’t the primary key of my orders table be the
          order number or some other meaningful column? Why use an artificial
          primary key such as id?”
          The reason is largely a practical one—the format of external data may
          change over time. For example, you might think that the ISBN of a book
          would make a good primary key in a table of books. After all, ISBNs are
          Report erratum Prepared exclusively for Don Francis
          PRIMARY KEYS AND IDS 198
          unique. But as this particular book is being written, the publishing industry
          in the US is gearing up for a major change as additional digits are
          added to all ISBNs.
          If we’d used the ISBN as the primary key in a table of books, we’d have to
          go through and update each row to reflect this change. But then we’d have
          another problem. There’ll be other tables in the database that reference
          rows in the books table via the primary key. We can’t change the key in the
          books table unless we first go through and update all of these references.
          And that will involve dropping foreign key constraints, updating tables,
          updating the books table, and finally reestablishing the constraints. All in
          all, something of a pain.
          If we use our own internal value as a primary key, things work out a lot
          better. No third party can come along and arbitrarily tell us to change
          things—we control our own keyspace. And if something such as the ISBN
          does need to change, it can change without affecting any of the existing
          relationships in the database. In effect, we’ve decoupled the knitting
          together of rows from the external representation of data in those rows.
          Now there’s nothing to say that we can’t expose the id value to our end
          users. In the orders table, we could externally call it an order id and print
          it on all the paperwork. But be careful doing this—at any time some regulator
          may come along and mandate that order ids must follow an externally
          imposed format, and you’d be back where you started.
          If you’re creating a new schema for a Rails application, you’ll probably
          want to go with the flow and give all of your tables an id column as their
          primary key. If you need to work with an existing schema, Active Record
          gives you a simple way of overriding the default name of the primary key
          for a table.
          class BadBook < ActiveRecord::Base
          set_primary_key "isbn"
          end
          Normally, Active Record takes care of creating new primary key values
          for records that you create and add to the database—they’ll be ascending
          integers (possibly with some gaps in the sequence). However, if you override
          the primary key column’s name, you also take on the responsibility
          of setting the primary key to a unique value before you save a new row.
          Perhaps surprisingly, you still set an attribute called id to do this. As far as
          As we’ll see later, join tables are not included in this advice—they should not have an id column.
          Active Record is concerned, the primary key attribute is always set using
          an attribute called id. The set_primary_key declaration sets the name of the
          column to use in the table. In the following code, we use an attribute
          called id even though the primary key in the database is isbn.
          book = BadBook.new
          book.id = "0-12345-6789"
          book.title = "My Great American Novel"
          book.save
          # ...
          book = BadBook.find("0-12345-6789")
          puts book.title # => "My Great American Novel"
          p book.attributes #=> {"isbn" =>"0-12345-6789",
          "title"=>"My Great American Novel"}
          Just to make things more confusing, the attributes of the model object
          have the column names isbn and title—id doesn’t appear. When you need
          to set the primary key, use id. At all other times, use the actual column
          name.

          posted @ 2006-05-11 11:41 wash 閱讀(207) | 評論 (0)編輯 收藏

          Accessing Attributes

          If a model object has an attribute named balance, you can access the
          attribute’s value using the indexing operator, passing it either a string or
          a symbol. Here we’ll use symbols.
          account[:balance] #=> return current value
          account[:balance] = 0.0 #=> set value of balance
          However, this is deprecated in normal code, as it considerably reduces
          your options should you want to change the underlying implementation
          of the attribute in the future. Instead, you should access values or model
          attributes using Ruby accessor methods.
          account.balance #=> return current value
          account.balance = 0.0 #=> set value of balance
          The value returned using these two techniques will be cast by Active
          Record to an appropriate Ruby type if possible (so, for example, if the
          database column is a timestamp, a Time object will be returned). If you
          want to get the raw value of an attribute, append _before_type_cast to the
          method form of its name, as shown in the following code.

          COLUMNS AND ATTRIBUTES 195
          David Says. . .
          Overriding Model Attributes
          Here’s an example of the benefits of using accessors to get at the
          attributes of models. Our account model will raise an exception immediately
          when someone tries to set a balance below a minimum value.
          class Account < ActiveRecord::Base
          def balance=(value)
          raise BalanceTooLow if value < MINIMUM_LEVEL
          self[:balance] = value
          end
          end
          account.balance_before_type_cast #=> "123.4", a string
          account.release_date_before_type_cast #=> "20050301"
          Finally, inside the code of the model itself, you can use the read_attribute( )
          and write_attribute( ) private methods. These take the attribute name as a
          string parameter.
          Boolean Attributes
          Some databases support a boolean column type, others don’t. This makes
          it hard for Active Record to abstract booleans. For example, if the underlying
          database has no boolean type, some developers use a char(1) column
          containing “t” or “f” to represent true or false. Others use integer columns,
          where 0 is false and 1 is true. Even if the database supports boolean types
          directly (such as MySQL and its bool column type), they might just be
          stored as 0 or 1 internally.
          The problem is that in Ruby the number 0 and the string “f” are both
          interpreted as true values in conditions.4 This means that if you use the
          value of the column directly, your code will interpret the column as true
          when you intended it to be false.
          # DON'T DO THIS
          user = Users.find_by_name("Dave")
          if user.superuser
          grant_privileges
          end
          4Ruby has a simple definition of truth. Any value that is not nil or the constant false is
          true.

          To query a column in a condition, you must append a question mark to
          the column’s name.
          # INSTEAD, DO THIS
          user = Users.find_by_name("Dave")
          if user.superuser?
          grant_privileges
          end
          This form of attribute accessor looks at the column’s value. It is interpreted
          as false only if it is the number zero; one of the strings "0", "f", "false",
          or "" (the empty string); a nil; or the constant false. Otherwise it is interpreted
          as true.
          If you work with legacy schemas or have databases in languages other than
          English, the definition of truth in the previous paragraph may not hold.
          In these cases, you can override the built-in definition of the predicate
          methods. For example, in Dutch, the field might contain J or N (for Ja or
          Nee). In this case, you could write
          class User < ActiveRecord::Base
          def superuser?
          self.superuser == 'J'
          end
          # . . .
          end
          Storing Structured Data
          It is sometimes convenient to store attributes containing arbitrary Ruby
          objects directly into database tables. One way that Active Record supports
          this is by serializing the Ruby object into a string (in YAML format) and
          storing that string in the database column corresponding to the attribute.
          In the schema, this column must be defined as type text.
          Because Active Record will normally map a character or text column to a
          plain Ruby string, you need to tell Active Record to use serialization if you
          want to take advantage of this functionality. For example, we might want
          to record the last five purchases made by our customers. We’ll create a
          table containing a text column to hold this information.
          File 6 create table purchases (
          id int not null auto_increment,
          name varchar(100) not null,
          last_five text,
          primary key (id)
          );
          In the Active Record class that wraps this table, we’ll use the serialize( )
          declaration to tell Active Record to marshal objects into and out of this
          column.
          File 8 class Purchase < ActiveRecord::Base
          serialize :last_five
          # ...
          end
          When we create new Purchase objects, we can assign any Ruby object to
          the last_five column. In this case, we set it to an array of strings.
          File 8 purchase = Purchase.new
          purchase.name = "Dave Thomas"
          purchase.last_five = [ 'shoes', 'shirt', 'socks', 'ski mask', 'shorts' ]
          purchase.save
          When we later read it in, the attribute is set back to an array.
          File 8 purchase = Purchase.find_by_name("Dave Thomas")
          pp purchase.last_five
          pp purchase.last_five[3]
          This code outputs
          ["shoes", "shirt", "socks", "ski mask", "shorts"]
          "ski mask"
          Although powerful and convenient, this approach is problematic if you
          ever need to be able to use the information in the serialized columns outside
          a Ruby application. Unless that application understands the YAML
          format, the column contents will be opaque to it. In particular, it will be
          difficult to use the structure inside these columns in SQL queries. You
          might instead want to consider using object aggregation, described in Section
          15.2, Aggregation, on page 247, to achieve a similar effect.

          posted @ 2006-05-11 11:09 wash 閱讀(203) | 評論 (0)編輯 收藏

          主站蜘蛛池模板: 渑池县| 泾源县| 喜德县| 新绛县| 始兴县| 海城市| 彭阳县| 宜兴市| 天等县| 古浪县| 龙里县| 平安县| 咸阳市| 海南省| 苍南县| 龙南县| 虹口区| 柳州市| 乌兰浩特市| 府谷县| 沙洋县| 白城市| 涿鹿县| 四会市| 南乐县| 凤庆县| 凤城市| 大渡口区| 印江| 瑞安市| 时尚| 延吉市| 东兴市| 论坛| 陈巴尔虎旗| 台南县| 东乌珠穆沁旗| 和平县| 平度市| 永康市| 宣化县|