액션뷰 (기본도우미 메소드)

IT(Old)/RubyOnRails 2008. 1. 22. 11:43
숫자 및 텍스트를 포맷하는 도우미 메소드

- number_with_delimiter(num(숫자에서 세자리마다 쉼표를 찍어줌)
  <%= number_woth_Delimiter(1562000) %>
  => 1,562,000

- number_with_precision(num, digits): 소수를 표시할 때, 소수점 이하 자리수를 제한하여 표시해줌, 두 번째 인자는 소수점 이하 자리수를 지정함. 두 번째 인자는 선택사항으로 지정하지 않으면 소수점이 세 자리까지 표시됨
  <% number_with_precision(200.0, 1 %>
  => 66.7
  <% number_With_precision(200.0/3) %>
  => 66.667

- number_to_human_size(num) : 숫자를 바이트로 계산하여, 사람이 읽기 편한 단위(Byte, KB, MB등)로 변환해줌
  <%= number_to_human_size(31270) %>
  => 30.5KB

- truncate(str,length) : 전체 문자열의 길이가 length를 넘지 않도록 str의 끝을 잘라줌
  <%= truncate("무궁화 꽃이 피었습니다", 10) %>
  => 무궁화 꽃이 ...

- highlight(str, word): str안의 텍스트에서 word로 넘겨받은 문자열이 나타날 때마다 <strong> 태그를 사용하여 강조해줌
  <%= highlight("무궁화 꽃이 피었습니다.", "꽃") %>
  => 무궁화 <strong class=highlight">꽃</strong>이 피었습니다.

- simple_format(str) : 텍스트를 HTML로 변환

이미지 태그 도우미 메소드
- image_tag(source, html_options): <img> 태그를 출력해줌, html_options 부분은 해시로 데이터를 전달받으며, :size, :class, :alt 옵션 등을 사용할 수 있다.

<%= image_tag("company_logo.gif", :size => "80x30",
                                                   :class => "logo",
                                                   :alt => "회사 로고") %>
<img src="/images/company_logo.gif" class="logo" width="80" height="30" alt="회사 로고" />

링크 도우미 메소드
- link_to(name, options, html_options) :<a>태그를 출력해줌. options 부분은 해시로 데이터를 전달받으며, :controller, :action, :id등 해당 라우팅의 URL패턴에 사용되는 모든 요소를 옵션으로 사용할 수 있다. html_options부분은 <a>태그에서 사용되는 html옵션을 해시로 전달받으며, :class, :popup, :confirm, :method등을 사용할 수 있다.

<%= link_to("프로필 보기",
                 {:controller => "users", :action => "show", :id => @user},
                 {:popup => ['Help', 'width=320, height=400'], :class => "info"}) %>

=>
<a href="/users/show/41" class="info" onclick="window.open(this.href, '프로필','width=320, height=400');
return false;">프로필 보기 </a>

세션과(session) 플래시(flash) 기능 팁

IT(Old)/RubyOnRails-Tip 2008. 1. 22. 09:08

1. session : session 메소드는 해시 객체를 리턴하는데, 이 해시가 바로 세션 데이터가 저장되는 장소이다.
사용자가 로그인 된 이후에는, sessoin[:user_id]이 현재 로그인된 사용자 ID를 리턴하게 된다. 만약 현재의 사용자가 로그인되어 있지 않다면, session[:user_id]는 nil을 리턴한다.

세션기능은 기본적으로 on 상태이기 때문에 이 기능을 필요치 않은 페이지에서는
각 컨트롤러 선언부 바로 밑에
session :off
을 사용하여 중지시킬수도 있다.

2. Flash : 플래시 기능이 유용한 것은 앞에서도 설명한 바와 같이 HTTP 프로토콜이 상태를 보존할 수 없는 프로토콜이기 때문이다. 플래시는 세션과는 다르게 웹 브라우저의 바로 다음 요청까지만 데이터를 보존한다. 즉 login 액션에서 플래시에 저장된 에러 메세지는 바로 다음 요청인 login_form 액션까지만 유지되고, 그 이후에는 자동으로 삭제된다. 플래시에 대한 자세한 내용은 5.5절 '플래시'에서 다루고 있다.


사용예제
class LoginController < ApplicationController

  def login_form
    reset_session
   
  end

  def login
    @user = User.find_by_login(params[:login])
   
    if @user && (@user.password == params[:password])
      session[:user_id] = @user.id
      redirect_to :action => "index"
    else
      flash[:error] = "로그인 ID나 비밀번호가 틀렸습니다!"
      redirect_to(:action => "index")
    end
  end

  def logout
    reset_session
    redirect_to(:action => "login_form")
  end

  def index
    if session[:user_id]
      render_text "#{User.find(session[:user_id]).name}님 환영합니다.!"
    else
      redirect_to :action => "login_form"
    end
  end
end

rails console사용하기 1 (activeRecord의 find 사용법)

IT(Old)/RubyOnRails 2008. 1. 21. 16:07
1.시작
ruby script/console
Loading development environment (Rails 2.0.2)
>>

위에서 >> 프롬프트는 루비의 irb프롬프트이다. 여기에서는 단순히 irb유틸리티를 실행한 것이 아니라
레일스 애플리케이션의 콘솔을 시작한 것이기 때문에, 앞에서 정의했던 User모델 클래스를 사용하는 것이
가능하다.

2. Data 입력
>> @user = User.new
=> #<User id: nil, name: nil, login: nil, password: nil, registered_on: nil>
>> @user.name = "jolaking"
=> "jolaking"
>> @user.login = "jola"
=> "jola"
>> @user.password = "jola"
=> "jola"
>> @user.registered_on = Date.today
=> Mon, 21 Jan 2008
>> @user.save
=> true     ==> 저장이 성공되었음을 표시한다.
사용자 삽입 이미지

Data 확인



다른방법
>>  @user = User.new(:name => "jolaking2",
?>  :login => "jola2",
?>  :password => "jola2",
?>  :registered_on => Date.today)
=> #<User id: nil, name: "jolaking2", login: "jola2", password: "jola2", registe
red_on: "2008-01-21">
>> @user.save
=> true
>>

사용자 삽입 이미지

3. Data Retrieve

?> @user = User.find(1)
=> #<User id: 1, name: "jolaking", login: "jola", password: "jola", registered_o
n: "2008-01-21">
>> @user = User.find(2)
=> #<User id: 2, name: "jolaking2", login: "jola2", password: "jola2", registere
d_on: "2008-01-21">
>> @user = User.find(3)
ActiveRecord::RecordNotFound: Couldn't find User with ID=3
        from c:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record
/base.rb:1267:in `find_one'
        from c:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record
/base.rb:1250:in `find_from_ids'
        from c:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record
/base.rb:504:in `find'
        from (irb):27
>>

주의할점 registered_on 메소드는 Date객체를 리턴하기 때문에 여기에서는 리턴된 Date 객체의
to_s 메소드를 호출하여 이를 문자열로 반환해야 된다.
find_by_xxxx 사용하기

?> @user = User.find_by_login("jola")
=> #<User id: 1, name: "jolaking", login: "jola", password: "jola", registered_o
n: "2008-01-21">
>> @user = User.find_by_login("jola2")
=> #<User id: 2, name: "jolaking2", login: "jola2", password: "jola2", registere
d_on: "2008-01-21">
>> @user = User.find_by_login("jola3")
=> nil >> 값이 없으면 nil

보다 복잡한 검색조건으로 찾기

?> str = "jola2"
=> "jola2"
>> @user = User.find(:first, :conditions => ["login=?", str])
=> #<User id: 2, name: "jolaking2", login: "jola2", password: "jola2", registere
d_on: "2008-01-21">
>>

여기서 :first는 첫번째 record의 return을 의미하고,
:all로 사용하면 배열로 여러 record를 받는다.

2가지 조건 이상 사용하면 다음과 같이 사용한다.
?> @user = User.find(:first, :conditions => ["login=? AND password=?" , "jola","jola"])
=> #<User id: 1, name: "jolaking", login: "jola", password: "jola", registered_on: "2008-01-21">


이쯤에서 사용되는 옵션을 정리하면
:first or :all = 첫번째 또는 전체
:conditions = Where 조건절 기술
:order        = 정렬방식
:limit          = 불러올 Record갯수
:offset        = 지정된 숫자만큼 레코드를 건너뛰고, 그다음부터 리턴
:readonly    = 리턴되는 레코드를 읽기 전용으로 만듦

conditions에 like 문을 사용하고자 한다면
:conditions = > ["login like ?", query + "%"]

직접 SQL문 입력가능

@group = Group.find_by_sql("SELECT ..... FROM aaa WHERE....");

다음에서 group값을 사용하고자 하면
@group[0].name 이런식으로
사용해야 된다.

Model 명명규칙 관례를 따르지 않을 경우

IT(Old)/RubyOnRails-Tip 2008. 1. 21. 15:32

User < ActiveREcord:Base
  set_table_name "user_tbl"
end

와 같이 강제로 table을 지정해 주어야 된다.


TIP : User  모델 클래스는 레일스 애플리케이션이 처음 구동될 때, 데이터베이스에 연결하여 users테이블의
필드 목록을 읽어들이게 된다. users 테이블의 필드 목록을 확인한 User 모델 클래스는 각 필드에 해당하는 접근자 메소드를 동적으로 정의하여 추가한다. 데이터 베이스 테이블의 필드를 확인하고 이에 해당하는 접근자
메소드를 동적으로 추가하는 User 모델 클래스의 기능으 ActiveRecord::Base클래스로 부터 상속되고 있다.

migration 문법

IT(Old)/RubyOnRails 2008. 1. 21. 15:08
1. 널값 허용X

create_table "groups" do |t|
  t.column "name", :string, Lnull => false
end

2. default값 지정
create_table "users" do |t|
  t.column "type", :string, Ldefault => "일반"
end

3. 문자열 컬럼 길이 지정
create_table "groups" do |t|
  t.column "name", :string, Llimit => 10
end

4. 숫자컬럼 길이지정
create_table "people" do |t|
  t.column "name", :string
  t.column "height", :decimal, Lprecision => 5, Lscale => 2
end

5. boolean
boolean은 TINYINT로 지정이 되어 true(1), false(2) 로 저장이 된다.

6. 테이블명 변경
rename_table "groups", categories"

7. 인덱스 추가
  add_index "groups", "name", :unique => true
  remove_index "groups", "name"

8. 기타 SQL
마이그레이션에서 지원하지 않는 비표준 기능은 execute를 사용해라

execute "ALTER TABLE people ADD CONSTRAINT fk_person_group"
 

시간/날짜 관련 표현식

IT(Old)/RubyOnRails-Tip 2008. 1. 21. 12:14

t = Time.now

t.strftime("%Y/%m/%d %H:%M:%S")
=>2008/01/21 12:13:30


t.strftime("%y/%m/%d %I:%M:%S %p");
=>08/01/21 12:13:30 PM

초를 더할때

t2 = t + 30

5일을 더할때
t3 = t + 60*60*24*5

크기로 비교 가능

t2 < t3


today = Data.today
christmas = Date.new(2007,12,25)

날짜는 +연산을 하면 일자가 더해진다.

3. 기본문법3(Containers, Blocks, and Iterators)

IT(Old)/RubyOnRails 2008. 1. 15. 16:01

1. Containers

DATA를 저장하는 Container객체에 대해 알아보자
이런저런 설명 빼고 어떻게 사용하는지만 보면 될 듯 싶다.

- Arrays

a = [ 3.14159, "pie", 99 ] 
a.type  » Array 
a.length  » 3 
a[0]  » 3.14159 
a[1]  » "pie" 
a[2]  » 99 
a[3]  » nil 
 
b = Array.new 
b.type  » Array 
b.length  » 0 
b[0] = "second" 
b[1] = "array" 
b  » ["second", "array"] 


이건 그냥 대략 이해 가고

a = [ 1, 3, 5, 7, 9 ] 
a[-1]  » 9 
a[-2]  » 7 
a[-99]  » nil


여기서 주의할 점은 -(마이너스)인덱스도 거꾸로 1까지만 가고 그 이상이 되면(-6) nil값을 return한다.

a = [ 1, 3, 5, 7, 9 ] 
a[1, 3]  » [3, 5, 7] 
a[3, 1]  » [7] 
a[-3, 2]  » [5, 7]
 

이것은 arrya[start, count] 방식으로 사용한다.

a = [ 1, 3, 5, 7, 9 ] 
a[1..3]  » [3, 5, 7] 
a[1...3]  » [3, 5] 
a[3..3]  » [7] 
a[-3..-1]  » [5, 7, 9]
 

.. 은 마지막것을 포함 ...은 마지막을 제외한다.

a = [ 1, 3, 5, 7, 9 ] » [1, 3, 5, 7, 9]
a[1] = 'bat' » [1, "bat", 5, 7, 9]
a[-3] = 'cat' » [1, "bat", "cat", 7, 9]
a[3] = [ 9, 8 ] » [1, "bat", "cat", [9, 8], 9]
a[6] = 99 » [1, "bat", "cat", [9, 8], 9, nil, 99]


마지막에 인덱스를 건더뛰게되면 중간에 빈것은 nil

a = [ 1, 3, 5, 7, 9 ] » [1, 3, 5, 7, 9]
a[2, 2] = 'cat' » [1, 3, "cat", 9]
a[2, 0] = 'dog' » [1, 3, "dog", "cat", 9]
a[1, 1] = [ 9, 8, 7 ] » [1, 9, 8, 7, "dog", "cat", 9]
a[0..3] = [] » ["dog", "cat", 9]
a[5] = 99 » ["dog", "cat", 9, nil, nil, 99]


여기서는 처음것은 index 두번째것은 length(0은 빈곳 삽입, 1은 한개만 replace, 2는 두개 replace)

- Hashes

h = { 'dog' => 'canine', 'cat' => 'feline', 'donkey' => 'asinine' } 
 
h.length  » 3 
h['dog']  » "canine" 
h['cow'] = 'bovine' 
h[12]    = 'dodecine' 
h['cat'] = 99 
h  » {"cow"=>"bovine", "cat"=>99, 12=>"dodecine", "donkey"=>"asinine", "dog"=>"canine"}
 

2. Implementing a SongList Container

class Song
 
  attr_reader :name, :artist, :duration
  def initialize(name, artist, duration)
    @name = name
    @artist = artist
    @duration = duration
  end
  def name
    @name
  end
  def artist
    @artist
  end
  def duration
    @duration
  end
  def duration=(newDuration)
    @duration = newDuration
  end
  def durationInMinutes
     @duration/60.0
   end
end

class SongList
  def initialize
    @songs = Array.new
  end
 
  def append(aSong)
    @songs.push(aSong)
    self
  end
 
  def deleteFirst
    @songs.shift
  end
  def deleteLast
    @songs.pop
  end
 
  def [] (key)
    if key.kind_of?(Integer)
      @songs[key]
    else
      # ...
    end
  end
end

list = SongList.new
list.
  append(Song.new('title1','artist1',1)).
  append(Song.new('title2','artist2',2)).
  append(Song.new('title3','artist3',3)).
  append(Song.new('title4','artist4',4))
 
 
#puts list.deleteFirst
#puts list.deleteFirst
#puts list.deleteFirst
#puts list.deleteFirst
#puts list.deleteFirst

#puts list[0]
#puts list[2]
#puts list[9]


여기서 shift 는 queue라 봤을때 처음값을 삭제
pop은 마지막것을 삭제한다 보면 된다.

key.kind_of?(Integer) 부분은 인자값을로 받은것이 정수인지 구분

3. Blocks and Iterators

위의것은 인덱스로만 검색하는 것이고 이제부터는 문자열로 검색 가능토록 만들어보자

총 3가지 방법이 있다.
첫번째는

class SongList
  def [](key)
    if key.kind_of?(Integer)
      return @songs[key]
    else
      for i in
0...@songs.length
        return @songs[i] if key == @songs[i].name
      end
    end
    return nil
  end
end


다른 언어에서와 같이 평범하다. 여기에 루비 문법을 적용해보면
두번째와 같다.

class SongList
  def [](key)
    if key.kind_of?(Integer)
      result = @songs[key]
    else
      result = @songs.find { |aSong| key == aSong.name }
    end
    return result
  end
end


어랏 간단해졌네... 하지만 이것도 맛배기.. 더 간단히 줄여보자
세번째는 다음과 같다.

class SongList
  def [](key)
    return @songs[key] if key.kind_of?(Integer)
    return @songs.find { |aSong| aSong.name == key }
  end
end


헐;;; 사람들이 루비 칭찬하는 이유를 알겠다.....
이제부터 나는 세번째 방법으로 할련다.

- Implementing Iterator

앞서 아래와 같이 yield의 간단한 사용법을 배웠다
def threeTimes
  yield
  yield
  yield
end
threeTimes { puts "Hello" }

 
produces: Hello
Hello
Hello


이것 응용한 것을 보면 다음과 같다.(아 머리 아파 하지 말자)

def fibUpTo(max)
  i1, i2 = 1, 1        # parallel assignment
  while i1 <= max
    yield i1
    i1, i2 = i2, i1+i2
  end
end
fibUpTo(1000) { |f| print f, " " }

produces: 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987

값의 흐름을 보면 간단하니깐
i1  i2
1    1
1    2
2    3
3    5
5    8
....
610 987
이런 형태로 값이 쌓인다.

주의해서 볼 것은 병렬로 값의 저장이 가능하다는 것과
yield로 자기를 호출한 것에 다시 값을 return 해 준다는 것.. 쫌만 쬐려보면 금방 이해 된다.

더 응용된 예제를 보자

class Array 
  def find 
    for i in 0...size 
      value = self[i] 
      return value if yield(value) 
    end 
    return nil 
  end 
end
 
 
[1, 3, 5, 7, 9].find {|v| v*v > 30 } 

위 예제는 find를 하면서 loop를 돌고
일방적으로 값을 넘기는 것이 아니고 서로 통신하고 잇따 보면 된다. 결과 값을 puts로 찍으면 7
설명이 길어지니 pass

또다른 형태의 iterator 방법을 보자

[ 1, 3, 5 ].each { |i| puts i }
 
produces: 1
3
5


각각의 값을 받고 1, 3, 5출력

puts ["H", "A", "L"].collect { |x| x.succ }

이것은 I B M 출력한다.
succ는 바로 다음 ascii코드를 뿌리는건가? 에랏 모르겠다.

4. Ruby Compared with C++ and Java

class Array 
  def inject(n) 
     each { |value| n = yield(n, value) } 
     n 
  end 
  def sum 
    inject(0) { |n, value| n + value } 
  end 
  def product 
    inject(1) { |n, value| n * value } 
  end 
end 
puts [ 1, 2, 3, 4, 5 ].sum  #≫ 15 
puts [ 1, 2, 3, 4, 5 ].product  #≫ 120


이것도 설명이 길어지므로 pass

5. Blocks for Transactions

Blocks can be used to define a chunk of code that must be run under some kind of transactional control. For example, you'll often open a file, do something with its contents, and then want to ensure that the file is closed when you finish. Although you can do this using conventional code, there's an argument for making the file responsible for closing itself. We can do this with blocks. A naive implementation (ignoring error handling) might look something like the following.

class File
  def File.openAndProcess(*args)
    f = File.open(*args)
    yield f
    f.close()
  end
end

File.openAndProcess("testfile", "r") do |aFile|
  print while aFile.gets
end

 
produces: This is line one
This is line two
This is line three
And so on...



This small example illustrates a number of techniques. The openAndProcess method is a class method---it may be called independent of any particular File object. We want it to take the same arguments as the conventional File.open method, but we don't really care what those arguments are. Instead, we specified the arguments as *args, meaning ``collect the actual parameters passed to the method into an array.'' We then call File.open, passing it *args as a parameter. This expands the array back into individual parameters. The net result is that openAndProcess transparently passes whatever parameters it received to File.open .

Once the file has been opened, openAndProcess calls yield, passing the open file object to the block. When the block returns, the file is closed. In this way, the responsibility for closing an open file has been passed from the user of file objects back to the files themselves.

Finally, this example uses do...end to define a block. The only difference between this notation and using braces to define blocks is precedence: do...end binds lower than ``{...}''. We discuss the impact of this on page 234.

The technique of having files manage their own lifecycle is so useful that the class File supplied with Ruby supports it directly. If File.open has an associated block, then that block will be invoked with a file object, and the file will be closed when the block terminates. This is interesting, as it means that File.open has two different behaviors: when called with a block, it executes the block and closes the file. When called without a block, it returns the file object. This is made possible by the method Kernel::block_given? , which returns true if a block is associated with the current method. Using it, you could implement File.open (again, ignoring error handling) using something like the following.

class File
  def File.myOpen(*args)
    aFile = File.new(*args)
    # If there's a block, pass in the file and close
    # the file when it returns
    if block_given?
      yield aFile
      aFile.close
      aFile = nil
    end
    return aFile
  end
end


6. Blocks Can Be Closures

Let's get back to our jukebox for a moment (remember the jukebox?). At some point we'll be working on the code that handles the user interface---the buttons that people press to select songs and control the jukebox. We'll need to associate actions with those buttons: press STOP and the music stops. It turns out that Ruby's blocks are a convenient way to do this. Let's start out by assuming that the people who made the hardware implemented a Ruby extension that gives us a basic button class. (We talk about extending Ruby beginning on page 169.)

bStart = Button.new("Start")
bPause = Button.new("Pause")

# ...

What happens when the user presses one of our buttons? In the Button class, the hardware folks rigged things so that a callback method, buttonPressed, will be invoked. The obvious way of adding functionality to these buttons is to create subclasses of Button and have each subclass implement its own buttonPressed method.

class StartButton < Button
  def initialize
    super("Start")       # invoke Button's initialize
  end
  def buttonPressed
    # do start actions...
  end
end

bStart = StartButton.new

There are two problems here. First, this will lead to a large number of subclasses. If the interface to Button changes, this could involve us in a lot of maintenance. Second, the actions performed when a button is pressed are expressed at the wrong level; they are not a feature of the button, but are a feature of the jukebox that uses the buttons. We can fix both of these problems using blocks.

class JukeboxButton < Button
  def initialize(label, &action)
    super(label)
    @action = action
  end
  def buttonPressed
    @action.call(self)
  end
end

bStart = JukeboxButton.new("Start") { songList.start }
bPause = JukeboxButton.new("Pause") { songList.pause }

The key to all this is the second parameter to JukeboxButton#initialize. If the last parameter in a method definition is prefixed with an ampersand (such as &action), Ruby looks for a code block whenever that method is called. That code block is converted to an object of class Proc and assigned to the parameter. You can then treat the parameter as any other variable. In our example, we assigned it to the instance variable @action. When the callback method buttonPressed is invoked, we use the Proc#call method on that object to invoke the block.

So what exactly do we have when we create a Proc object? The interesting thing is that it's more than just a chunk of code. Associated with a block (and hence a Proc object) is all the context in which the block was defined: the value of self, and the methods, variables, and constants in scope. Part of the magic of Ruby is that the block can still use all this original scope information even if the environment in which it was defined would otherwise have disappeared. In other languages, this facility is called a closure.

Let's look at a contrived example. This example uses the method proc, which converts a block to a Proc object.

def nTimes(aThing) 
  return proc { |n| aThing * n } 
end 
 
p1 = nTimes(23) 
p1.call(3)  » 69 
p1.call(4)  » 92 
p2 = nTimes("Hello ") 
p2.call(3)  » "Hello Hello Hello "
 

The method nTimes returns a Proc object that references the method's parameter, aThing. Even though that parameter is out of scope by the time the block is called, the parameter remains accessible to the block



2. 기본문법2(class, object and variables)

IT(Old)/RubyOnRails 2008. 1. 15. 14:23

1. Class, Object and Variables(루비)

class Song
  def initialize(name, artist, duration)
     @name = name
     @artist = artist
     @duration = duration
  end
end

initialize는 Ruby에서 특별한 method다. Song.new로 객체를 생성할때 new뒤에 붙는 파라미터들은
initialize메소드로 들어가게된다.

aSong = Song.new{"Bicylops", "Fleck", 260}

예제)
class Song
  def initialize(name, artist, duration)
    @name = name
    @artist = artist
    @duration = duration
  end
 
  def to_s
    "Song:
#{@name}--#{@artist} (#{@duration})"
  end
end

aSong = Song.new("Bicylops", "Fleck", 260)
aSong.to_s
>> Song: Bicylops--Fleck (260)



2. Inheritance and Messages

class KaraokeSong < Song
  def initialize(name, artist, duration, lyrics)
     super(name, artist, duration)
     @lyrics = lyrics
  end
end

"< Song" 은 KaraokeSong이 Song의 sub클래스임을 의미한다.
다시한번

class Song
  def initialize(name, artist, duration)
    @name = name
    @artist = artist
    @duration = duration
  end
 
  def to_s
    "Song:
#{@name}--#{@artist} (#{@duration})"
  end
end

class KaraokeSong < Song
  def initialize(name, artist, duration, lyrics)
    super(name, artist, duration)
    @lyrics = lyrics
  end
 
  def to_s
    "Song:
#{@name}--#{@artist} (#{@duration}) #{@lyrics}"
  end
end

aSong = Song.new("Bicylops", "Fleck", 260)
puts aSong.to_s

bSong = KaraokeSong.new("My Way", "Sinatra", 225, "And new, the...")
puts bSong.to_s

>>
Song: Bicylops--Fleck (260)
Song: My Way--Sinatra (225) And new, the...

이것을 다시 Ruby 문법으로 간단하게 바꿔보자

KaraokeSong의 to_s를
"Song: #{@name}--#{@artist} (#{@duration}) #{@lyrics}"  => super + " #{@lyrics}"
로 바꾸면 더욱 간단해 진다.

3. Inheritance and Mixins

ruby는 단일상속만 지원하지만 많은수의 mixins기능을 포함할 수 잇따
(몬말인지는 나중에 설명한다... ㅡ.ㅡ)

4. Object and Attributes

앞서 작성한 song객체의 state는 private상태이다. 다른 곳에서 부를수가 없다는 말이겠지

class Song
 
  attr_reader :name, :artist, :duration
  def initialize(name, artist, duration)
    @name = name
    @artist = artist
    @duration = duration
  end
 
  def name
    @name
  end
   
  def artist
    @artist
  end
   
  def duration
    @duration
  end
end

aSong = Song.new("Bicylops", "Fleck", 260)
puts aSong.artist
puts aSong.name
puts aSong.duration


로칼변수를 write하기 위해서는

  def duration=(newDuration)
    @duration = newDuration
  end
또는
  attr_writer :duration

을 사용해라(주의 def duration=(newDuration) 에 스페이스는 없어야된다.)

5. Virtual Attributes

class Song
  def durationInMinutes
     @duration/60.0
  end
end

aSong.durationInMinues

처럼 가상의 변수를 만들어 사용할 수 잇따.

6. Class Variables and Class Methods

- class variables

class Song
  @@plays = 0
  def initialize(name, artist, duration)
    @name     = name
    @artist   = artist
    @duration = duration
    @plays    = 0
  end
  def play
    @plays += 1
    @@plays += 1
    "This  song: #@plays plays. Total #@@plays plays."
  end
end


s1 = Song.new("Song1", "Artist1", 234)  # test songs..
s2 = Song.new("Song2", "Artist2", 345)
s1.play » "This  song: 1 plays. Total 1 plays."
s2.play » "This  song: 1 plays. Total 2 plays."
s1.play » "This  song: 2 plays. Total 3 plays."
s1.play » "This  song: 3 plays. Total 4 plays."


- class methods

class SongList
  MaxTime = 5*60           #  5 minutes
  def SongList.isTooLong(aSong)
    return aSong.duration > MaxTime
  end
end
song1 = Song.new("Bicylops", "Fleck", 260)
SongList.isTooLong(song1) » false
song2 = Song.new("The Calling", "Santana", 468)
SongList.isTooLong(song2) » true


7. Singletons and Other Constructors

singletons를 사용하기 위해서는 new의 사용을 막고,
create같은 method를 사용해라.

class Logger
  private_class_method :new
  @@logger = nil
  def Logger.create
    @@logger = new unless @@logger
    @@logger
  end
end

puts Logger.create.id
puts Logger.create.id
>>
22918100
22918100

class Shape
  def Shape.triangle(sideLength)
    Shape.new(3, sideLength*3)
  end
  def Shape.square(sideLength)
    Shape.new(4, sideLength*4)
  end
end


8. Access Control

- public methods : 누구나 호출가능
- protected methods : 상속받은 sub class만 호출가능
- private methods : 외부에서는 호출할 수 없음

하지만 Ruby는 다른 OO언어들과는 다르다. Access control은 프로그램이 실행될 때 동적으로 결정된다.
당신은 제한된 mothod를 실행하기 시도할때만 당신은 이 규칙을 위반할 수 있다.

Specifying Access Control
public, protected, private를 사용하여 class나 module정의할때 access level을 정의할 수 있다.

class MyClass

      def method1    # default is 'public'
        #...
      end

  protected          # subsequent methods will be 'protected'

      def method2    # will be 'protected'
        #...
      end

  private            # subsequent methods will be 'private'

      def method3    # will be 'private'
        #...
      end

  public             # subsequent methods will be 'public'

      def method4    # and this will be 'public'
        #...
      end
end


다른 방법으로는

class MyClass

  def method1
  end

  # ... and so on

  public    :method1, :method4
  protected :method2
  private   :method3
end


클래스의 initialize method는 자동으로 private로 선언된다.

class Accounts

  private

    def debit(account, amount)
      account.balance -= amount
    end
    def credit(account, amount)
      account.balance += amount
    end

  public

    #...
    def transferToSavings(amount)
      debit(@checking, amount)
      credit(@savings, amount)
    end
    #...
end



class Account
  attr_reader :balance       # accessor method 'balance'

  protected :balance         # and make it protected

  def greaterBalanceThan(other)
    return @balance > other.balance
  end
end


9. Variables

person = "Tim"
puts person.id
puts person.type
puts person
>>
22918640
String
Tim



person1 = "Tim"
person2 = person1
person1[0] = 'J'
puts person1
puts person2
>>
Jim
Jim

person1 = "Tim"
person2 = person1.dup
person1[0] = 'J'
puts person1
puts person2
>>
Jim
Tim

person1 = "Tim"
person2 = person1
person1.freeze    # prevent modifications to the object
person2[0] = "j"
>>
Logger.rb:4:in `[]=': can't modify frozen string (TypeError)
















1. 기본문법1 (Ruby.new)

IT(Old)/RubyOnRails 2008. 1. 15. 11:15

1 .객체 생성
생성자라는 것에 의해 객체가 생성됨. new가 standard constructor

song1 = Song.new("Ruby Tuesday")
song2 = Song.new("Enveloped in Python")
# and so on

2. method call

"gin joint".length     >> 9
"Rick".index("c")    >> 2
-1942.abs              >> 1942
sam.play(aSong)    >> "duh dum, da dum de dum ..."

3. A method that return a string

def sayGoodnight(name)
  result  = "Goodnight, " + name
  return result
end

# Time for bed ...
puts sayGoodnight("John-Boy")
puts sayGoodnight("Mary-Ellen")

>> Goodnight, John-Boy
>> Goodnight, Mary-Ellen

puts sayGoodnight "John-Boy1"
puts sayGoodnight("John-Boy2")
puts (sayGoodnight "John-Boy3")
puts (sayGoodnight ("John-Boy4"))

>> Goodnight, John-Boy1
>> Goodnight, John-Boy2
>> Goodnight, John-Boy3
>> Goodnight, John-Boy4

4. double-quoted strings

- ""안에서 개행문자는 \n을 사용한다.
puts "And Goodnight, \nGrandma"

>> And Goodnight,
>> Grandma

- ""안에서 변수는 #{expression} 을사용한다
def sayGoodnight(name)
  result = "Goodnight, #{name}:
  return result
end


5. 명명규칙

Local variables, method paramethers 그리고 method names은 소문자로 시작되어야 한다.
class, module , constants는 대문자로 시작하자.
global variables$를 이름앞에 붙인다.
instance variables@을 이름앞에 붙인다.
class variables@@을 이름앞에 붙인다.

local : name, fishAndChips, x_axis, thx1138, _26
global : $debug, $CUSTOMER, $_, $plan9, $Global
instance : @name, @point_1, @X, @_, @plan9
Class : @@total, @@symtab, @@N, @@x_pos, @@SINGLE
Constatns and Class Names : PI, FeetPerMile, String, MyClass, Jazz_Song


6. 배열과 해쉬

배열과 해쉬는 indexed collections이다. 둘다 key를 사용하여 접근 가능하다.
배열은 정수를 키로, 해쉬는 객체를 키로 사용한다.
이것들은 서로 다른타입을(integer, string, floating point number) 객체로 가질수 있다.

a = [1, 'cat', 3.14] # array with three elements
# access the first element
a[0]     >> 1
# set the third element
a[2] = nil
# dump out the array
a         >>  [ 1, "cat", nil]

Array.new를 사용하여 생성할 수도 있다.
empty1 = []
empty2 = Array.new

때때로 단어들을 사용하는 배열은 귀찮을 수가 있다. 왜냐 모두 quote로 묶어야 돼니까.
그걸위해 %w를 사용해라

a = %w{ ant bee cat dog elk }
a[0]    >> "ant"
a[3]    >> "dog"

해쉬를 사용하는 것은 배열과 비슷하다.

instSection = {
  'cello' => 'string',
  'clarinet' => 'woodwind',
  'drum => 'percussion',
  'oboe'  => 'woodwind',
  'trumpet' =>'brass',
  'violin'  => 'string'
}

instSection['oboe']  >> "woodwind:
instSection['cello']  >> "string"
instSection['bassoon'] >> nil

세번째 nil은 존재하지 않는다는 것을 의미한다.
nil은 조건식에서 false를 의미할 때 사용한다. 이 기본값을 바꾸길 원할것이다.
그거시 기본값으로 0을 가지긴 쉽다. 생성자로 생성할때 empty경우 기본값을 세팅하면 되거든

histogram = Hash.new(0)
histogram['key1']               >> 0
histogram['key1'] = histogram['key1'] + 1
histogram['key1']               >> 1

7. 조건문 반복문

일반적인 사용예)

if count > 10
  puts "Try again"
elsif tries == 3
  puts "You lose"
else
  puts "Enter a number"
end

while weight < 100 and numPallets <= 30
  pallet = nextPallet()
  weight += pallet.weight
  numPallets += 1
end

간단히 바꾸기
if radiation > 3000
  puts "Danger, Will Robinson"
end
=>
puts "Danger, Will Robinson" if radiation > 3000

while square < 1000
  square = square * square
end
=>
square = square*square while square < 1000


8. 정규표현식(Regualr Expressions)

/Perl|Python/  => /P(erl|ython)/
/\d\d:\d\d:\d\d/   # a time such as 12:34:56
/Perl.*Python/              # Perl, zero or more other chars, then Python
/Perl\s+Python/          # Perl, one or more spaces, then Python
/Ruby (Perl|Python)/    # Ruby, a space, and either Perl or Python

만약 해당되는 문자열이 =~ 다음에 포함되어 있으면(같은것이 아니고 포함) true, 아니면 false(nil)

line = 'Perl1'
if line =~ /Perl|Python/
  puts "aaa"
else
  puts "bbb"
end

>> aaa

문자열 변환

line = 'Perl123'
puts line.sub(/Perl/, 'Ruby')
>> Ruby123

9. Blocks and Iterators

{puts "Hello" }           # this is a block

do                            #
  club.enroll(person)  # and so is this
  person.socialize     #
end                         #

yield를 사용해서 method는 한번이상 invoke될수 있다.

def callBlock
  yield
  yield
end

callBlock { puts "In the block" }
>>
In the block
In the block

In the block이 두번 실행되엇다.
yield는 "|" 사이에 있는 파라미터를 받을수 있다.

def callBlock
  yield ,
end
callBlock { |, | ... }

Iterator사용
a = %w(ant bee cat dog elk)     # create an array
a.each {|animal| puts animal } # iterate over the contents
>>
ant
bee
cat
dog
elk


['cat','dog','horse'].each do |animal|
   print animal, " -- "
end
>> cat -- dog -- horse --

5.times {print "*"}
3.upto(6) {|i| print i}
('a'..'e').each{|char| print char}
>> *****3456abcde


10. Reading and 'Riting

printf "Number: %5.2f, String:%s", 1.23, "hello"
>> Number:  1.23, String:hello
C와 비슷

line = gets
print line

gets는 콘솔로부터 값을 받는구나


while gets
   if /Ruby/
     print
   end
end

이건 Ruby라는 단어를 치면 Ruby를 출력
>>
asdf
fds
sdf
g
Ruby
Ruby
asdf
Ruby
Ruby
ruby
Ruby
Ruby