[scala] String으로 Class method 호출하기. ruby의 send처럼..

Programming/scala 2016.03.23 23:53

스트링 문자를 통해서 해당 문자에 해당하는 클래스를 호출해보자.


나도 잘 모르기때문에 역시나 구글사마의 도움을 받아.. 스택오버플로우를 뒤지기 시작했다.

http://stackoverflow.com/questions/2060395/is-there-any-scala-feature-that-allows-you-to-call-a-method-whose-name-is-stored


2가지 방식으로 호출이 가능한데..

자바의 refliction기법으로 한다면 아래와 같다.


class A {
  def cat(s1: String, s2: String) = s1 + " " + s2
}
val a = new A
val hi = "Hello"
val all = "World"
val method = a.getClass.getMethod("cat",hi.getClass,all.getClass)
method.invoke(a,hi,all)


Scala를 통해서 하고자 한다면..

case class Caller[T>:Null<:AnyRef](klass:T) {
  def call(methodName:String,args:AnyRef*):AnyRef = {
    def argtypes = args.map(_.getClass)
    def method = klass.getClass.getMethod(methodName, argtypes: _*)
    method.invoke(klass,args: _*)
  }
}
implicit def anyref2callable[T>:Null<:AnyRef](klass:T):Caller[T] = new Caller(klass)
a call ("cat","Hi","there")
이러하다..


저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

[javascript] convert underscore to camelcase

Programming 2015.05.29 14:47

var a = ["animal_cat","animal_dog","animal_lion"];

for(var i = 0 ; i < a.length ; i++){

a[i] = a[i].replace(/_([a-z])/g, function (g) { return g[1].toUpperCase(); });

}


저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

[scala] Pattern matching / Type matching

Programming/scala 2015.04.08 14:03

스칼라를 쓰면서 이해하는데 많은 공이 들어가는게 matching이다.


매칭을 쓰다가 괴팍한 문제에 부닥혔다.

type matching을 이용하여 case문을 쓰려고 한 코드다.

val t = ("string", Int)


t match {

case t:(String, String) => println("second value is string")

case t:(String, Int) => println("second value is int")

case _ => println("others.")

}


이렇게 하면 두번째 매칭인 (String,Int)에 매칭이되어 "second value is int"가  나와야 할것 같은데.. 첫번째인 "second value is string" 가 나온다.

그러면서 워닝이 뜨지.

<console>:10: warning: fruitless type test: a value of type (String, Int) cannot also be a (String, String) (but still might match its erasure)

              case t:(String, String) => println("second value is string")

                     ^

<console>:11: warning: unreachable code

              case t:(String, Int) => println("second value is int")

이는 튜플의 제네릭 타입 추론이 불가능해서 인걸로 추측이 되는데..

t match ...  요부분에서 t의 타입을 정해주지 않았기에 컴파일러가 튜플 내의 타입을 추론하지 못한것 같다.

만약에 tuple이 val t = ("string", 0) 이렇게 되어있다면

아래와 같은 type matching이 가능하다.

(t: (Any, Any))  match {

  case (t1: String, t2: String) => "this is string"

  case (t1: String, t2: Int) => "this is int"

  case _ => "this is other!"

}

왠지 위의 코드로 원래의 문제였던 val t = ("string", Int)를 넣으면 제대로 매칭할 것 같지만.. 실제로 돌려보면 아니다...

실제로 돌려보면 아무것도 매칭되지 않아서 "this is other!"가 출력된다.


이를통해서 하나의 tuple내에서 type matching과 pattern matching이 병합적으로 사용되지 못함을 알 수 있다.

Int의 type은 Int가 아니고 object scala.Int이기 때문이다.


결국은 type matching으로 해결하기 힘들게 되어 나온코드는 pattern matching을 사용하는 코드였다.

val t = ("string", Int)

t._2 match {

case Float => "this is Float"

case Int => "this is Integer"

case _ => "this is other!"

}


두번째 인자인 Int == Int 이기 때문이다.

하지만 이것도 근본적인 해결책은 아니다. 왜냐하면

val t = ("string", "string val") 형태로 들어온것을 잡아내기 위해서는 

case "string val" 이라고 명시되어야 하기 때문이다.

case String 이라고 쓸수 없으니까...

결국 제일 마지막의 _ 에 걸릴수 밖에 없다.





저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

[ROR] benchmark sort

Programming 2014.07.02 17:18

#!/usr/bin/ruby 

require 'benchmark' 

ary = [] 
1000.times { 
 ary << {:bar => rand(1000)} 


n = 500 
Benchmark.bm(20) do |x| 
 x.report("sort")               { n.times { ary.sort{ |a,b| b[:bar] <=> a[:bar] } } } 
 x.report("sort reverse")       { n.times { ary.sort{ |a,b| a[:bar] <=> b[:bar] }.reverse } } 
 x.report("sort_by -a[:bar]")   { n.times { ary.sort_by{ |a| -a[:bar] } } } 
 x.report("sort_by a[:bar]*-1") { n.times { ary.sort_by{ |a| a[:bar]*-1 } } } 
 x.report("sort_by.reverse!")   { n.times { ary.sort_by{ |a| a[:bar] }.reverse } } 
end 



                           user     system      total        real

sort                   0.940000   0.000000   0.940000 (  0.940155)

sort reverse           0.970000   0.000000   0.970000 (  0.969526)

sort_by -a[:bar]       0.390000   0.010000   0.400000 (  0.400547)

sort_by a[:bar]*-1     0.390000   0.000000   0.390000 (  0.391629)

sort_by.reverse!       0.370000   0.000000   0.370000 (  0.373811)


저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

[ROR] rails generate not null 제약조건 변경.

Programming 2014.06.18 11:20


> rails g migration change_field_name_to_table_name field_name:data_type


class ChangeFieldNameToTableName < ActiveRecord::Migration

  def change

    change_column_null(:table_name, :field_name, true)

  end

end






저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

[ROR] ActiveRecord module - create on duplicate key update

Programming 2014.03.03 22:13

module ActiveRecord

  # = Active Record Persistence

  module Persistence

    extend ActiveSupport::Concern


    def create_on_duplicate_key_update!(keys)

      #keys = duplicate_keys.is_a? Array ? duplicate_keys : [duplicate_keys] 

      keys.collect! { |k| k.to_s }

      klass = self.class

      attributes_with_values = arel_attributes_with_values_for_create(attribute_names)

      column_hash = klass.connection.schema_cache.columns_hash klass.table_name

      db_columns_with_values = []

      attributes_with_values.map { |attr, value|

        real_column = column_hash[attr.name]

        db_columns_with_values << [real_column, value] if value.present?

        if (value.blank? && ['created_at', 'updated_at'].include?(real_column.name))

          now = DateTime.now

          db_columns_with_values << [real_column, now]

          self.send("#{attr.name}=",now)

        end

      }

      sql = "INSERT INTO #{self.class.quoted_table_name} (#{db_columns_with_values.collect{|c| klass.connection.quote_column_name(c.first.name)}.join(', ')})"

      sql << " VALUES (#{db_columns_with_values.collect{|c| klass.connection.quote(c.last)}.join(', ')}) "

      sql << " ON DUPLICATE KEY UPDATE "

      sql << sql_for_on_duplicate_key_update(keys,db_columns_with_values)


      klass.connection.execute sql

    end


    private

    def sql_for_on_duplicate_key_update(keys,db_columns_with_values)

      connection = self.class.connection

      results = []

      db_columns_with_values.map do |column, value|

        results << "#{self.class.quoted_table_name}.#{connection.quote_column_name(column.name)}=#{connection.quote(value, column)}" unless keys.include?(column.name)

      end

      results.join(',')

    end

  end

end



저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

[ROR 팁]Rails rake test에서 특정 기능만 테스트하기!

Programming 2014.02.26 16:59

rake test를 돌릴 때 원하는 기능의 테스트들만 한번에 돌리고자 할 때... 유용한 팁


만약 디렉토리가


test/controllers/blog_controller_test.rb

test/models/blog_model_test.rb

test/jobs/blog_job_test.rb 

...


이런식으로 작성이 되었다면 blog에 관련된 테스트만 돌리고싶다! 는 needs다.


namespace :test do

  rule "" do |t|

    # rake test:blog

    if /test:(.*)(:([^.]+))?$/.match(t.name)

      arguments = t.name.split(":")[1..-1]

      file_name = arguments.first

      test_name = arguments[1..-1]


      Dir["test/**/#{file_name}*_test.rb"].each {|path|

        result = `ruby -Ilib:test #{path}`

        puts "=========[ #{file_name} test result ]================================================================"

        puts result[result.index("Finished tests")..-1].to_s.split('\n')

        puts "==========================================================================================="

      }

    end

  end

end




아무 .rake 파일을 만들어서 lib/tasks 밑에 넣어주면 된다.

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

[Java] 초간단 Mail 보내기 클래스.

Programming 2013.01.07 19:47

초간단 Mail 보내기 클래스 만들기!


pom.xml

<dependency>

<groupId>javax.mail</groupId>

<artifactId>mail</artifactId>

<version>1.4.3</version>

</dependency>


MailSender.java

import javax.mail.MessagingException;

import javax.mail.internet.MimeMessage;


import org.springframework.mail.javamail.JavaMailSenderImpl;

import org.springframework.mail.javamail.MimeMessageHelper;


import com.devsisters.game.oven2.domain.IapErrorReport;


public class MailSender {

    private static final String HOST = "smtp.host.com";

    private static final String EMAIL_ADDR = "sender@host.com";

    private static final String EMAIL_PWD = "password";


    private static JavaMailSenderImpl sender = new JavaMailSenderImpl();


    public static void SendIapErrorMail(String title, String msg, String toMail) {


sender.setHost(MAIL_HOST);

sender.setUsername(EMAIL_ADDR);

sender.setPassword(EMAIL_PWD);


MimeMessage message = sender.createMimeMessage();

MimeMessageHelper helper = new MimeMessageHelper(message);

try {

    helper.setTo(toMail);

    helper.setSubject(title);

    helper.setText(msg);

    helper.setFrom(EMAIL_ADDR);

    sender.send(message);

} catch (MessagingException e) {

    e.printStackTrace();

}

    }

}


저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

리눅스 한달 이상 지난 로그 삭제 크론.

Programming 2012.12.12 17:56

한달이 지나 쓸모없는 로그를 삭제하는 크론을 등록할때.


00 02 * * * /usr/bin/find /usr/local/tomcat/log -atime +30 -exec rm -f {} \;


저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

Java server side Apple IAP and Google Play IAP verification class

Programming 2012.12.12 15:45



import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.io.OutputStreamWriter;

import java.net.URL;

import java.net.URLConnection;

import java.security.InvalidKeyException;

import java.security.KeyFactory;

import java.security.NoSuchAlgorithmException;

import java.security.PublicKey;

import java.security.Signature;

import java.security.SignatureException;

import java.security.spec.InvalidKeySpecException;

import java.security.spec.X509EncodedKeySpec;


import org.apache.commons.codec.binary.Base64;

import org.apache.commons.lang.StringUtils;

import org.apache.log4j.Logger;

import org.codehaus.jackson.JsonNode;

import org.codehaus.jackson.map.ObjectMapper;


/**

 * Apple IAP and Google Play In-app Billing Verification Class

 *

 */

public class IapVerification {

    static Logger logger = Logger.getLogger(IapVerification.class);

    public static final String VERIFICATION_URL_REAL = "https://buy.itunes.apple.com/verifyReceipt";

    public static final String VERIFICATION_URL_SANDBOX = "https://sandbox.itunes.apple.com/verifyReceipt";

    /**

     * @return int

     * @param receipt

     * @param isTest

     * @return 0: fail, 1: success, -1 : urus hacking

     * @throws IOException

     */

    public static int verifyApplePurchase(String receipt, boolean isTest) throws IOException {

String returnedString ;

if (isTest)

{

    returnedString = verifyAppleReceiptData(VERIFICATION_URL_SANDBOX, receipt);

} else {

    returnedString = verifyAppleReceiptData(VERIFICATION_URL_REAL, receipt);

}


ObjectMapper mapper = new ObjectMapper();

JsonNode resultObject = mapper.readTree(returnedString);

int resultStatus = Integer.parseInt(resultObject.get("status").toString());


if (resultStatus != 0)

{

    // urus hacking check.

    try {

String decodedText = new String(Base64.decodeBase64(receipt

.getBytes()), "UTF-8");

if (decodedText != null && decodedText.startsWith("com.urus")) {

    return -1;

}

    } catch (Exception base64DecodeException) {

logger.error(base64DecodeException.getMessage());

    }

    return 0;


}

return 1;

    }

    /**

     * @author Kim Seong Su

     * @return String

     * @param urladdress

     * @param receiptData

     * @return result string

     * @throws IOException

     */

    private static String verifyAppleReceiptData(String urladdress, String receiptData) throws IOException  {

URL url = null;

URLConnection conn = null;

OutputStreamWriter osw = null;

BufferedReader br = null;

StringBuffer sb = new StringBuffer();


try {

    String jsonData = "{" +

                    "\"receipt-data\" : \"" + receiptData + "\"," +

                 "}";

    url = new URL(urladdress);

    conn = url.openConnection();

    conn.setDoOutput(true);

    osw = new OutputStreamWriter(conn.getOutputStream());

    osw.write(jsonData);

    osw.flush();


    // Get the response

    br = new BufferedReader(

    new InputStreamReader(conn.getInputStream()));

    String line;

    sb = new StringBuffer();

    while ((line = br.readLine()) != null) {

// Process line...

sb.append(line);

    }

} finally {

    if (osw != null)

osw.close();

    if (br != null)

br.close();

}


return sb.toString();

    }


    // --------------------- For Android --------------------------//


    private static final String KEY_FACTORY_ALGORITHM = "RSA";

    private static final String SIGNATURE_ALGORITHM = "SHA1withRSA";


    /**

     * Verifies that the data was signed with the given signature, and returns

     * the verified purchase. The data is in JSON format and signed

     * with a private key. The data also contains the {@link PurchaseState}

     * and product ID of the purchase.

     * @param base64PublicKey the base64-encoded public key to use for verifying.

     * @param signedData the signed JSON string (signed, not encrypted)

     * @param signature the signature for the data, signed with the private key

     */

    public static boolean verifyAndroidPurchase(String base64PublicKey, String signedData, String signature) {

        if (signedData == null) {

            return false;

        }


        boolean verified = false;

        if (!StringUtils.isEmpty(signature)) {

            PublicKey key = IapVerification.generatePublicKey(base64PublicKey);

            verified = IapVerification.verifyAndroidSignedData(key, signedData, signature);

            if (!verified) {

                return false;

            }

        }

        return true;

    }


    /**

     * Generates a PublicKey instance from a string containing the

     * Base64-encoded public key.

     *

     * @param encodedPublicKey Base64-encoded public key

     * @throws IllegalArgumentException if encodedPublicKey is invalid

     */

    public static PublicKey generatePublicKey(String encodedPublicKey) {

        try {

            byte[] decodedKey = Base64.decodeBase64(encodedPublicKey);

            KeyFactory keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM);

            return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey));

        } catch (NoSuchAlgorithmException e) {

            throw new RuntimeException(e);

        } catch (InvalidKeySpecException e) {

            throw new IllegalArgumentException(e);

        }

    }


    /**

     * Verifies that the signature from the server matches the computed

     * signature on the data.  Returns true if the data is correctly signed.

     *

     * @param publicKey public key associated with the developer account

     * @param signedData signed data from server

     * @param signature server signature

     * @return true if the data and signature match

     */

    public static boolean verifyAndroidSignedData(PublicKey publicKey, String signedData, String signature) {

        Signature sig;

        try {

            sig = Signature.getInstance(SIGNATURE_ALGORITHM);

            sig.initVerify(publicKey);

            sig.update(signedData.getBytes());

            if (!sig.verify(Base64.decodeBase64(signature))) {

                return false;

            }

            return true;

        } catch (NoSuchAlgorithmException e) {

            logger.error(e.getMessage());

        } catch (InvalidKeyException e) {

            logger.error(e.getMessage());

        } catch (SignatureException e) {

            logger.error(e.getMessage());

        }

        return false;

    }

}


저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License


티스토리 툴바